Bug 848507 - Support searching DXR in mach; r=gps
DONTBUILD because this is NPOTB.
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* vim: set ts=2 et sw=2 tw=78: *//* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. *//* parsing of CSS stylesheets, based on a token stream from the CSS scanner */#include"mozilla/DebugOnly.h"#include"nsCSSParser.h"#include"nsCSSProps.h"#include"nsCSSKeywords.h"#include"nsCSSScanner.h"#include"mozilla/css/ErrorReporter.h"#include"mozilla/css/Loader.h"#include"mozilla/css/StyleRule.h"#include"mozilla/css/ImportRule.h"#include"nsCSSRules.h"#include"mozilla/css/NameSpaceRule.h"#include"nsTArray.h"#include"nsCSSStyleSheet.h"#include"mozilla/css/Declaration.h"#include"nsStyleConsts.h"#include"nsNetUtil.h"#include"nsCOMPtr.h"#include"nsString.h"#include"nsReadableUtils.h"#include"nsIAtom.h"#include"nsColor.h"#include"nsCSSPseudoClasses.h"#include"nsCSSPseudoElements.h"#include"nsINameSpaceManager.h"#include"nsXMLNameSpaceMap.h"#include"nsError.h"#include"nsIMediaList.h"#include"nsStyleUtil.h"#include"nsIPrincipal.h"#include"prprf.h"#include"nsContentUtils.h"#include"nsAutoPtr.h"#include"CSSCalc.h"#include"nsMediaFeatures.h"#include"nsLayoutUtils.h"usingnamespacemozilla;// Flags for ParseVariant method#define VARIANT_KEYWORD 0x000001 // K#define VARIANT_LENGTH 0x000002 // L#define VARIANT_PERCENT 0x000004 // P#define VARIANT_COLOR 0x000008 // C eCSSUnit_Color, eCSSUnit_Ident (e.g. "red")#define VARIANT_URL 0x000010 // U#define VARIANT_NUMBER 0x000020 // N#define VARIANT_INTEGER 0x000040 // I#define VARIANT_ANGLE 0x000080 // G#define VARIANT_FREQUENCY 0x000100 // F#define VARIANT_TIME 0x000200 // T#define VARIANT_STRING 0x000400 // S#define VARIANT_COUNTER 0x000800 //#define VARIANT_ATTR 0x001000 //#define VARIANT_IDENTIFIER 0x002000 // D#define VARIANT_IDENTIFIER_NO_INHERIT 0x004000 // like above, but excluding// 'inherit' and 'initial'#define VARIANT_AUTO 0x010000 // A#define VARIANT_INHERIT 0x020000 // H eCSSUnit_Initial, eCSSUnit_Inherit#define VARIANT_NONE 0x040000 // O#define VARIANT_NORMAL 0x080000 // M#define VARIANT_SYSFONT 0x100000 // eCSSUnit_System_Font#define VARIANT_GRADIENT 0x200000 // eCSSUnit_Gradient#define VARIANT_TIMING_FUNCTION 0x400000 // cubic-bezier() and steps()#define VARIANT_ALL 0x800000 //#define VARIANT_IMAGE_RECT 0x01000000 // eCSSUnit_Function// This is an extra bit that says that a VARIANT_ANGLE allows unitless zero:#define VARIANT_ZERO_ANGLE 0x02000000 // unitless zero for angles#define VARIANT_CALC 0x04000000 // eCSSUnit_Calc#define VARIANT_ELEMENT 0x08000000 // eCSSUnit_Element#define VARIANT_POSITIVE_DIMENSION 0x10000000 // Only lengths greater than 0.0#define VARIANT_NONNEGATIVE_DIMENSION 0x20000000 // Only lengths greater than or equal to 0.0// Common combinations of variants#define VARIANT_AL (VARIANT_AUTO | VARIANT_LENGTH)#define VARIANT_LP (VARIANT_LENGTH | VARIANT_PERCENT)#define VARIANT_LN (VARIANT_LENGTH | VARIANT_NUMBER)#define VARIANT_AH (VARIANT_AUTO | VARIANT_INHERIT)#define VARIANT_AHLP (VARIANT_AH | VARIANT_LP)#define VARIANT_AHI (VARIANT_AH | VARIANT_INTEGER)#define VARIANT_AHK (VARIANT_AH | VARIANT_KEYWORD)#define VARIANT_AHKLP (VARIANT_AHLP | VARIANT_KEYWORD)#define VARIANT_AHL (VARIANT_AH | VARIANT_LENGTH)#define VARIANT_AHKL (VARIANT_AHK | VARIANT_LENGTH)#define VARIANT_HK (VARIANT_INHERIT | VARIANT_KEYWORD)#define VARIANT_HKF (VARIANT_HK | VARIANT_FREQUENCY)#define VARIANT_HKI (VARIANT_HK | VARIANT_INTEGER)#define VARIANT_HKL (VARIANT_HK | VARIANT_LENGTH)#define VARIANT_HKLP (VARIANT_HK | VARIANT_LP)#define VARIANT_HKLPO (VARIANT_HKLP | VARIANT_NONE)#define VARIANT_HL (VARIANT_INHERIT | VARIANT_LENGTH)#define VARIANT_HI (VARIANT_INHERIT | VARIANT_INTEGER)#define VARIANT_HLP (VARIANT_HL | VARIANT_PERCENT)#define VARIANT_HLPN (VARIANT_HLP | VARIANT_NUMBER)#define VARIANT_HLPO (VARIANT_HLP | VARIANT_NONE)#define VARIANT_HTP (VARIANT_INHERIT | VARIANT_TIME | VARIANT_PERCENT)#define VARIANT_HMK (VARIANT_HK | VARIANT_NORMAL)#define VARIANT_HC (VARIANT_INHERIT | VARIANT_COLOR)#define VARIANT_HCK (VARIANT_HK | VARIANT_COLOR)#define VARIANT_HUK (VARIANT_HK | VARIANT_URL)#define VARIANT_HUO (VARIANT_INHERIT | VARIANT_URL | VARIANT_NONE)#define VARIANT_AHUO (VARIANT_AUTO | VARIANT_HUO)#define VARIANT_HPN (VARIANT_INHERIT | VARIANT_PERCENT | VARIANT_NUMBER)#define VARIANT_PN (VARIANT_PERCENT | VARIANT_NUMBER)#define VARIANT_ALPN (VARIANT_AL | VARIANT_PN)#define VARIANT_HN (VARIANT_INHERIT | VARIANT_NUMBER)#define VARIANT_HON (VARIANT_HN | VARIANT_NONE)#define VARIANT_HOS (VARIANT_INHERIT | VARIANT_NONE | VARIANT_STRING)#define VARIANT_LPN (VARIANT_LP | VARIANT_NUMBER)#define VARIANT_UK (VARIANT_URL | VARIANT_KEYWORD)#define VARIANT_UO (VARIANT_URL | VARIANT_NONE)#define VARIANT_ANGLE_OR_ZERO (VARIANT_ANGLE | VARIANT_ZERO_ANGLE)#define VARIANT_LPCALC (VARIANT_LENGTH | VARIANT_CALC | VARIANT_PERCENT)#define VARIANT_LNCALC (VARIANT_LENGTH | VARIANT_CALC | VARIANT_NUMBER)#define VARIANT_LPNCALC (VARIANT_LNCALC | VARIANT_PERCENT)#define VARIANT_IMAGE (VARIANT_URL | VARIANT_NONE | VARIANT_GRADIENT | \ VARIANT_IMAGE_RECT | VARIANT_ELEMENT)// This lives here because it depends on the above macros.constuint32_tnsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands]={#define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, \ stylestruct_, stylestructoffset_, animtype_) \ parsevariant_,#include"nsCSSPropList.h"#undef CSS_PROP};//----------------------------------------------------------------------namespace{// Rule processing functiontypedefvoid(*RuleAppendFunc)(css::Rule*aRule,void*aData);staticvoidAssignRuleToPointer(css::Rule*aRule,void*aPointer);staticvoidAppendRuleToSheet(css::Rule*aRule,void*aParser);// Your basic top-down recursive descent style parser// The exposed methods and members of this class are precisely those// needed by nsCSSParser, far below.classCSSParserImpl{public:CSSParserImpl();~CSSParserImpl();nsresultSetStyleSheet(nsCSSStyleSheet*aSheet);nsresultSetQuirkMode(boolaQuirkMode);nsresultSetChildLoader(mozilla::css::Loader*aChildLoader);// Clears everything set by the above Set*() functions.voidReset();nsresultParseSheet(constnsAString&aInput,nsIURI*aSheetURI,nsIURI*aBaseURI,nsIPrincipal*aSheetPrincipal,uint32_taLineNumber,boolaAllowUnsafeRules);nsresultParseStyleAttribute(constnsAString&aAttributeValue,nsIURI*aDocURL,nsIURI*aBaseURL,nsIPrincipal*aNodePrincipal,css::StyleRule**aResult);nsresultParseDeclarations(constnsAString&aBuffer,nsIURI*aSheetURL,nsIURI*aBaseURL,nsIPrincipal*aSheetPrincipal,css::Declaration*aDeclaration,bool*aChanged);nsresultParseRule(constnsAString&aRule,nsIURI*aSheetURL,nsIURI*aBaseURL,nsIPrincipal*aSheetPrincipal,css::Rule**aResult);nsresultParseProperty(constnsCSSPropertyaPropID,constnsAString&aPropValue,nsIURI*aSheetURL,nsIURI*aBaseURL,nsIPrincipal*aSheetPrincipal,css::Declaration*aDeclaration,bool*aChanged,boolaIsImportant,boolaIsSVGMode);nsresultParseMediaList(constnsSubstring&aBuffer,nsIURI*aURL,// for error reportinguint32_taLineNumber,// for error reportingnsMediaList*aMediaList,boolaHTMLMode);boolParseColorString(constnsSubstring&aBuffer,nsIURI*aURL,// for error reportinguint32_taLineNumber,// for error reportingnsCSSValue&aValue);nsresultParseSelectorString(constnsSubstring&aSelectorString,nsIURI*aURL,// for error reportinguint32_taLineNumber,// for error reportingnsCSSSelectorList**aSelectorList);already_AddRefed<nsCSSKeyframeRule>ParseKeyframeRule(constnsSubstring&aBuffer,nsIURI*aURL,uint32_taLineNumber);boolParseKeyframeSelectorString(constnsSubstring&aSelectorString,nsIURI*aURL,// for error reportinguint32_taLineNumber,// for error reportingInfallibleTArray<float>&aSelectorList);boolEvaluateSupportsDeclaration(constnsAString&aProperty,constnsAString&aValue,nsIURI*aDocURL,nsIURI*aBaseURL,nsIPrincipal*aDocPrincipal);boolEvaluateSupportsCondition(constnsAString&aCondition,nsIURI*aDocURL,nsIURI*aBaseURL,nsIPrincipal*aDocPrincipal);protected:classnsAutoParseCompoundProperty;friendclassnsAutoParseCompoundProperty;classnsAutoFailingSupportsRule;friendclassnsAutoFailingSupportsRule;classnsAutoSuppressErrors;friendclassnsAutoSuppressErrors;voidAppendRule(css::Rule*aRule);friendvoidAppendRuleToSheet(css::Rule*,void*);// calls AppendRule/** * This helper class automatically calls SetParsingCompoundProperty in its * constructor and takes care of resetting it to false in its destructor. */classnsAutoParseCompoundProperty{public:nsAutoParseCompoundProperty(CSSParserImpl*aParser):mParser(aParser){NS_ASSERTION(!aParser->IsParsingCompoundProperty(),"already parsing compound property");NS_ASSERTION(aParser,"Null parser?");aParser->SetParsingCompoundProperty(true);}~nsAutoParseCompoundProperty(){mParser->SetParsingCompoundProperty(false);}private:CSSParserImpl*mParser;};/** * This helper class conditionally sets mInFailingSupportsRule to * true if aCondition = false, and resets it to its original value in its * destructor. If we are already somewhere within a failing @supports * rule, passing in aCondition = true does not change mInFailingSupportsRule. */classnsAutoFailingSupportsRule{public:nsAutoFailingSupportsRule(CSSParserImpl*aParser,boolaCondition):mParser(aParser),mOriginalValue(aParser->mInFailingSupportsRule){if(!aCondition){mParser->mInFailingSupportsRule=true;}}~nsAutoFailingSupportsRule(){mParser->mInFailingSupportsRule=mOriginalValue;}private:CSSParserImpl*mParser;boolmOriginalValue;};/** * Auto class to set aParser->mSuppressErrors to the specified value * and restore it to its original value later. */classnsAutoSuppressErrors{public:nsAutoSuppressErrors(CSSParserImpl*aParser,boolaSuppressErrors=true):mParser(aParser),mOriginalValue(aParser->mSuppressErrors){mParser->mSuppressErrors=aSuppressErrors;}~nsAutoSuppressErrors(){mParser->mSuppressErrors=mOriginalValue;}private:CSSParserImpl*mParser;boolmOriginalValue;};// the caller must hold on to aString until parsing is donevoidInitScanner(nsCSSScanner&aScanner,css::ErrorReporter&aReporter,nsIURI*aSheetURI,nsIURI*aBaseURI,nsIPrincipal*aSheetPrincipal);voidReleaseScanner(void);boolIsSVGMode()const{returnmScanner->IsSVGMode();}boolGetToken(boolaSkipWS);voidUngetToken();boolExpectSymbol(PRUnicharaSymbol,boolaSkipWS);boolExpectEndProperty();boolCheckEndProperty();nsSubstring*NextIdent();// returns true when the stop symbol is found, and false for EOFboolSkipUntil(PRUnicharaStopSymbol);voidSkipUntilOneOf(constPRUnichar*aStopSymbolChars);voidSkipRuleSet(boolaInsideBraces);boolSkipAtRule(boolaInsideBlock);boolSkipDeclaration(boolaCheckForBraces);voidPushGroup(css::GroupRule*aRule);voidPopGroup();boolParseRuleSet(RuleAppendFuncaAppendFunc,void*aProcessData,boolaInsideBraces=false);boolParseAtRule(RuleAppendFuncaAppendFunc,void*aProcessData,boolaInAtRule);boolParseCharsetRule(RuleAppendFuncaAppendFunc,void*aProcessData);boolParseImportRule(RuleAppendFuncaAppendFunc,void*aProcessData);boolParseURLOrString(nsString&aURL);boolGatherMedia(nsMediaList*aMedia,boolaInAtRule);boolParseMediaQuery(boolaInAtRule,nsMediaQuery**aQuery,bool*aHitStop);boolParseMediaQueryExpression(nsMediaQuery*aQuery);voidProcessImport(constnsString&aURLSpec,nsMediaList*aMedia,RuleAppendFuncaAppendFunc,void*aProcessData);boolParseGroupRule(css::GroupRule*aRule,RuleAppendFuncaAppendFunc,void*aProcessData);boolParseMediaRule(RuleAppendFuncaAppendFunc,void*aProcessData);boolParseMozDocumentRule(RuleAppendFuncaAppendFunc,void*aProcessData);boolParseNameSpaceRule(RuleAppendFuncaAppendFunc,void*aProcessData);voidProcessNameSpace(constnsString&aPrefix,constnsString&aURLSpec,RuleAppendFuncaAppendFunc,void*aProcessData);boolParseFontFaceRule(RuleAppendFuncaAppendFunc,void*aProcessData);boolParseFontDescriptor(nsCSSFontFaceRule*aRule);boolParseFontDescriptorValue(nsCSSFontDescaDescID,nsCSSValue&aValue);boolParsePageRule(RuleAppendFuncaAppendFunc,void*aProcessData);boolParseKeyframesRule(RuleAppendFuncaAppendFunc,void*aProcessData);already_AddRefed<nsCSSKeyframeRule>ParseKeyframeRule();boolParseKeyframeSelectorList(InfallibleTArray<float>&aSelectorList);boolParseSupportsRule(RuleAppendFuncaAppendFunc,void*aProcessData);boolParseSupportsCondition(bool&aConditionMet);boolParseSupportsConditionNegation(bool&aConditionMet);boolParseSupportsConditionInParens(bool&aConditionMet);boolParseSupportsConditionInParensInsideParens(bool&aConditionMet);boolParseSupportsConditionTerms(bool&aConditionMet);enumSupportsConditionTermOperator{eAnd,eOr};boolParseSupportsConditionTermsAfterOperator(bool&aConditionMet,SupportsConditionTermOperatoraOperator);enumnsSelectorParsingStatus{// we have parsed a selector and we saw a token that cannot be// part of a selector:eSelectorParsingStatus_Done,// we should continue parsing the selector:eSelectorParsingStatus_Continue,// we saw an unexpected token or token value,// or we saw end-of-file with an unfinished selector:eSelectorParsingStatus_Error};nsSelectorParsingStatusParseIDSelector(int32_t&aDataMask,nsCSSSelector&aSelector);nsSelectorParsingStatusParseClassSelector(int32_t&aDataMask,nsCSSSelector&aSelector);// aPseudoElement and aPseudoElementArgs are the location where// pseudo-elements (as opposed to pseudo-classes) are stored;// pseudo-classes are stored on aSelector. aPseudoElement and// aPseudoElementArgs must be non-null iff !aIsNegated.nsSelectorParsingStatusParsePseudoSelector(int32_t&aDataMask,nsCSSSelector&aSelector,boolaIsNegated,nsIAtom**aPseudoElement,nsAtomList**aPseudoElementArgs,nsCSSPseudoElements::Type*aPseudoElementType);nsSelectorParsingStatusParseAttributeSelector(int32_t&aDataMask,nsCSSSelector&aSelector);nsSelectorParsingStatusParseTypeOrUniversalSelector(int32_t&aDataMask,nsCSSSelector&aSelector,boolaIsNegated);nsSelectorParsingStatusParsePseudoClassWithIdentArg(nsCSSSelector&aSelector,nsCSSPseudoClasses::TypeaType);nsSelectorParsingStatusParsePseudoClassWithNthPairArg(nsCSSSelector&aSelector,nsCSSPseudoClasses::TypeaType);nsSelectorParsingStatusParsePseudoClassWithSelectorListArg(nsCSSSelector&aSelector,nsCSSPseudoClasses::TypeaType);nsSelectorParsingStatusParseNegatedSimpleSelector(int32_t&aDataMask,nsCSSSelector&aSelector);// If aStopChar is non-zero, the selector list is done when we hit// aStopChar. Otherwise, it's done when we hit EOF.boolParseSelectorList(nsCSSSelectorList*&aListHead,PRUnicharaStopChar);boolParseSelectorGroup(nsCSSSelectorList*&aListHead);boolParseSelector(nsCSSSelectorList*aList,PRUnicharaPrevCombinator);enum{eParseDeclaration_InBraces=1<<0,eParseDeclaration_AllowImportant=1<<1};enumnsCSSContextType{eCSSContext_General,eCSSContext_Page};css::Declaration*ParseDeclarationBlock(uint32_taFlags,nsCSSContextTypeaContext=eCSSContext_General);boolParseDeclaration(css::Declaration*aDeclaration,uint32_taFlags,boolaMustCallValueAppended,bool*aChanged,nsCSSContextTypeaContext=eCSSContext_General);boolParseProperty(nsCSSPropertyaPropID);boolParsePropertyByFunction(nsCSSPropertyaPropID);boolParseSingleValueProperty(nsCSSValue&aValue,nsCSSPropertyaPropID);enumPriorityParsingStatus{ePriority_None,ePriority_Important,ePriority_Error};PriorityParsingStatusParsePriority();#ifdef MOZ_XULboolParseTreePseudoElement(nsAtomList**aPseudoElementArgs);#endifvoidInitBoxPropsAsPhysical(constnsCSSProperty*aSourceProperties);// Property specific parsing routinesboolParseBackground();structBackgroundParseState{nsCSSValue&mColor;nsCSSValueList*mImage;nsCSSValuePairList*mRepeat;nsCSSValueList*mAttachment;nsCSSValueList*mClip;nsCSSValueList*mOrigin;nsCSSValueList*mPosition;nsCSSValuePairList*mSize;BackgroundParseState(nsCSSValue&aColor,nsCSSValueList*aImage,nsCSSValuePairList*aRepeat,nsCSSValueList*aAttachment,nsCSSValueList*aClip,nsCSSValueList*aOrigin,nsCSSValueList*aPosition,nsCSSValuePairList*aSize):mColor(aColor),mImage(aImage),mRepeat(aRepeat),mAttachment(aAttachment),mClip(aClip),mOrigin(aOrigin),mPosition(aPosition),mSize(aSize){};};boolParseBackgroundItem(BackgroundParseState&aState);boolParseValueList(nsCSSPropertyaPropID);// a single value prop-idboolParseBackgroundRepeat();boolParseBackgroundRepeatValues(nsCSSValuePair&aValue);boolParseBackgroundPosition();// ParseBoxPositionValues parses the CSS 2.1 background-position syntax,// which is still used by some properties. See ParseBackgroundPositionValues// for the css3-background syntax.boolParseBoxPositionValues(nsCSSValuePair&aOut,boolaAcceptsInherit,boolaAllowExplicitCenter=true);// deprecatedboolParseBackgroundPositionValues(nsCSSValue&aOut,boolaAcceptsInherit);boolParseBackgroundSize();boolParseBackgroundSizeValues(nsCSSValuePair&aOut);boolParseBorderColor();boolParseBorderColors(nsCSSPropertyaProperty);voidSetBorderImageInitialValues();boolParseBorderImageRepeat(boolaAcceptsInherit);// If ParseBorderImageSlice returns false, aConsumedTokens indicates// whether or not any tokens were consumed (in other words, was the property// in error or just not present). If ParseBorderImageSlice returns true// aConsumedTokens is always true.boolParseBorderImageSlice(boolaAcceptsInherit,bool*aConsumedTokens);boolParseBorderImageWidth(boolaAcceptsInherit);boolParseBorderImageOutset(boolaAcceptsInherit);boolParseBorderImage();boolParseBorderSpacing();boolParseBorderSide(constnsCSSPropertyaPropIDs[],boolaSetAllSides);boolParseDirectionalBorderSide(constnsCSSPropertyaPropIDs[],int32_taSourceType);boolParseBorderStyle();boolParseBorderWidth();boolParseCalc(nsCSSValue&aValue,int32_taVariantMask);boolParseCalcAdditiveExpression(nsCSSValue&aValue,int32_t&aVariantMask);boolParseCalcMultiplicativeExpression(nsCSSValue&aValue,int32_t&aVariantMask,bool*aHadFinalWS);boolParseCalcTerm(nsCSSValue&aValue,int32_t&aVariantMask);boolRequireWhitespace();#ifdef MOZ_FLEXBOX// For "flex" shorthand property, defined in CSS3 FlexboxboolParseFlex();#endif// for 'clip' and '-moz-image-region'boolParseRect(nsCSSPropertyaPropID);boolParseColumns();boolParseContent();boolParseCounterData(nsCSSPropertyaPropID);boolParseCursor();boolParseFont();boolParseFontWeight(nsCSSValue&aValue);boolParseOneFamily(nsAString&aFamily,bool&aOneKeyword);boolParseFamily(nsCSSValue&aValue);boolParseFontFeatureSettings(nsCSSValue&aValue);boolParseFontSrc(nsCSSValue&aValue);boolParseFontSrcFormat(InfallibleTArray<nsCSSValue>&values);boolParseFontRanges(nsCSSValue&aValue);boolParseListStyle();boolParseMargin();boolParseMarks(nsCSSValue&aValue);boolParseTransform(boolaIsPrefixed);boolParseOutline();boolParseOverflow();boolParsePadding();boolParseQuotes();boolParseSize();boolParseTextDecoration();boolParseTextDecorationLine(nsCSSValue&aValue);boolParseTextOverflow(nsCSSValue&aValue);boolParseShadowItem(nsCSSValue&aValue,boolaIsBoxShadow);boolParseShadowList(nsCSSPropertyaProperty);boolParseTransitionProperty();boolParseTransitionTimingFunctionValues(nsCSSValue&aValue);boolParseTransitionTimingFunctionValueComponent(float&aComponent,charaStop,boolaCheckRange);boolParseTransitionStepTimingFunctionValues(nsCSSValue&aValue);enumParseAnimationOrTransitionShorthandResult{eParseAnimationOrTransitionShorthand_Values,eParseAnimationOrTransitionShorthand_Inherit,eParseAnimationOrTransitionShorthand_Error};ParseAnimationOrTransitionShorthandResultParseAnimationOrTransitionShorthand(constnsCSSProperty*aProperties,constnsCSSValue*aInitialValues,nsCSSValue*aValues,size_taNumProperties);boolParseTransition();boolParseAnimation();boolParsePaint(nsCSSPropertyaPropID);boolParseDasharray();boolParseMarker();boolParsePaintOrder();// Reused utility parsing routinesvoidAppendValue(nsCSSPropertyaPropID,constnsCSSValue&aValue);boolParseBoxProperties(constnsCSSPropertyaPropIDs[]);boolParseGroupedBoxProperty(int32_taVariantMask,nsCSSValue&aValue);boolParseDirectionalBoxProperty(nsCSSPropertyaProperty,int32_taSourceType);boolParseBoxCornerRadius(constnsCSSPropertyaPropID);boolParseBoxCornerRadii(constnsCSSPropertyaPropIDs[]);int32_tParseChoice(nsCSSValueaValues[],constnsCSSPropertyaPropIDs[],int32_taNumIDs);boolParseColor(nsCSSValue&aValue);boolParseColorComponent(uint8_t&aComponent,int32_t&aType,charaStop);// ParseHSLColor parses everything starting with the opening '('// up through and including the aStop char.boolParseHSLColor(nscolor&aColor,charaStop);// ParseColorOpacity will enforce that the color ends with a ')'// after the opacityboolParseColorOpacity(uint8_t&aOpacity);boolParseEnum(nsCSSValue&aValue,constint32_taKeywordTable[]);boolParseVariant(nsCSSValue&aValue,int32_taVariantMask,constint32_taKeywordTable[]);boolParseNonNegativeVariant(nsCSSValue&aValue,int32_taVariantMask,constint32_taKeywordTable[]);boolParseOneOrLargerVariant(nsCSSValue&aValue,int32_taVariantMask,constint32_taKeywordTable[]);boolParseCounter(nsCSSValue&aValue);boolParseAttr(nsCSSValue&aValue);boolSetValueToURL(nsCSSValue&aValue,constnsString&aURL);boolTranslateDimension(nsCSSValue&aValue,int32_taVariantMask,floataNumber,constnsString&aUnit);boolParseImageRect(nsCSSValue&aImage);boolParseElement(nsCSSValue&aValue);boolParseColorStop(nsCSSValueGradient*aGradient);boolParseLinearGradient(nsCSSValue&aValue,boolaIsRepeating,boolaIsLegacy);boolParseRadialGradient(nsCSSValue&aValue,boolaIsRepeating,boolaIsLegacy);boolIsLegacyGradientLine(constnsCSSTokenType&aType,constnsString&aId);boolParseGradientColorStops(nsCSSValueGradient*aGradient,nsCSSValue&aValue);voidSetParsingCompoundProperty(boolaBool){mParsingCompoundProperty=aBool;}boolIsParsingCompoundProperty(void)const{returnmParsingCompoundProperty;}/* Functions for transform Parsing */boolParseSingleTransform(boolaIsPrefixed,nsCSSValue&aValue,bool&aIs3D);boolParseFunction(constnsString&aFunction,constint32_taAllowedTypes[],uint16_taMinElems,uint16_taMaxElems,nsCSSValue&aValue);boolParseFunctionInternals(constint32_taVariantMask[],uint16_taMinElems,uint16_taMaxElems,InfallibleTArray<nsCSSValue>&aOutput);/* Functions for transform-origin/perspective-origin Parsing */boolParseTransformOrigin(boolaPerspective);/* Find and return the namespace ID associated with aPrefix. If aPrefix has not been declared in an @namespace rule, returns kNameSpaceID_Unknown. */int32_tGetNamespaceIdForPrefix(constnsString&aPrefix);/* Find the correct default namespace, and set it on aSelector. */voidSetDefaultNamespaceOnSelector(nsCSSSelector&aSelector);// Current token. The value is valid after calling GetToken and invalidated// by UngetToken.nsCSSTokenmToken;// Our scanner.nsCSSScanner*mScanner;// Our error reporter.css::ErrorReporter*mReporter;// The URI to be used as a base for relative URIs.nsCOMPtr<nsIURI>mBaseURI;// The URI to be used as an HTTP "Referer" and for error reporting.nsCOMPtr<nsIURI>mSheetURI;// The principal of the sheet involvednsCOMPtr<nsIPrincipal>mSheetPrincipal;// The sheet we're parsing intonsRefPtr<nsCSSStyleSheet>mSheet;// Used for @import rulesmozilla::css::Loader*mChildLoader;// not ref counted, it owns us// Sheet section we're in. This is used to enforce correct ordering of the// various rule types (eg the fact that a @charset rule must come before// anything else). Note that there are checks of similar things in various// places in nsCSSStyleSheet.cpp (e.g in insertRule, RebuildChildList).enumnsCSSSection{eCSSSection_Charset,eCSSSection_Import,eCSSSection_NameSpace,eCSSSection_General};nsCSSSectionmSection;nsXMLNameSpaceMap*mNameSpaceMap;// weak, mSheet owns it// After an UngetToken is done this flag is true. The next call to// GetToken clears the flag.boolmHavePushBack:1;// True if we are in quirks mode; false in standards or almost standards modeboolmNavQuirkMode:1;// True when the hashless color quirk applies.boolmHashlessColorQuirk:1;// True when the unitless length quirk applies.boolmUnitlessLengthQuirk:1;// True if unsafe rules should be allowedboolmUnsafeRulesEnabled:1;// True if viewport units should be allowed.boolmViewportUnitsEnabled:1;// True for parsing media lists for HTML attributes, where we have to// ignore CSS comments.boolmHTMLMediaMode:1;// This flag is set when parsing a non-box shorthand; it's used to not apply// some quirks during shorthand parsingboolmParsingCompoundProperty:1;// True if we are somewhere within a @supports rule whose condition is// false.boolmInFailingSupportsRule:1;// True if we will suppress all parse errors (except unexpected EOFs).// This is used to prevent errors for declarations inside a failing// @supports rule.boolmSuppressErrors:1;// Stack of rule groups; used for @media and such.InfallibleTArray<nsRefPtr<css::GroupRule>>mGroupStack;// During the parsing of a property (which may be a shorthand), the data// are stored in |mTempData|. (It is needed to ensure that parser// errors cause the data to be ignored, and to ensure that a// non-'!important' declaration does not override an '!important'// one.)nsCSSExpandedDataBlockmTempData;// All data from successfully parsed properties are placed into |mData|.nsCSSExpandedDataBlockmData;public:// Used from nsCSSParser constructors and destructorsCSSParserImpl*mNextFree;};staticvoidAssignRuleToPointer(css::Rule*aRule,void*aPointer){css::Rule**pointer=static_cast<css::Rule**>(aPointer);NS_ADDREF(*pointer=aRule);}staticvoidAppendRuleToSheet(css::Rule*aRule,void*aParser){CSSParserImpl*parser=(CSSParserImpl*)aParser;parser->AppendRule(aRule);}#define REPORT_UNEXPECTED(msg_) \ { if (!mSuppressErrors) mReporter->ReportUnexpected(#msg_); }#define REPORT_UNEXPECTED_P(msg_, param_) \ { if (!mSuppressErrors) mReporter->ReportUnexpected(#msg_, param_); }#define REPORT_UNEXPECTED_TOKEN(msg_) \ { if (!mSuppressErrors) mReporter->ReportUnexpected(#msg_, mToken); }#define REPORT_UNEXPECTED_TOKEN_CHAR(msg_, ch_) \ { if (!mSuppressErrors) mReporter->ReportUnexpected(#msg_, mToken, ch_); }#define REPORT_UNEXPECTED_EOF(lf_) \ mReporter->ReportUnexpectedEOF(#lf_)#define REPORT_UNEXPECTED_EOF_CHAR(ch_) \ mReporter->ReportUnexpectedEOF(ch_)#define OUTPUT_ERROR() \ mReporter->OutputError()#define CLEAR_ERROR() \ mReporter->ClearError()CSSParserImpl::CSSParserImpl():mToken(),mScanner(nullptr),mReporter(nullptr),mChildLoader(nullptr),mSection(eCSSSection_Charset),mNameSpaceMap(nullptr),mHavePushBack(false),mNavQuirkMode(false),mHashlessColorQuirk(false),mUnitlessLengthQuirk(false),mUnsafeRulesEnabled(false),mViewportUnitsEnabled(true),mHTMLMediaMode(false),mParsingCompoundProperty(false),mInFailingSupportsRule(false),mSuppressErrors(false),mNextFree(nullptr){}CSSParserImpl::~CSSParserImpl(){mData.AssertInitialState();mTempData.AssertInitialState();}nsresultCSSParserImpl::SetStyleSheet(nsCSSStyleSheet*aSheet){if(aSheet!=mSheet){// Switch to using the new sheet, if anymGroupStack.Clear();mSheet=aSheet;if(mSheet){mNameSpaceMap=mSheet->GetNameSpaceMap();}else{mNameSpaceMap=nullptr;}}elseif(mSheet){mNameSpaceMap=mSheet->GetNameSpaceMap();}returnNS_OK;}nsresultCSSParserImpl::SetQuirkMode(boolaQuirkMode){mNavQuirkMode=aQuirkMode;returnNS_OK;}nsresultCSSParserImpl::SetChildLoader(mozilla::css::Loader*aChildLoader){mChildLoader=aChildLoader;// not ref counted, it owns usreturnNS_OK;}voidCSSParserImpl::Reset(){NS_ASSERTION(!mScanner,"resetting with scanner active");SetStyleSheet(nullptr);SetQuirkMode(false);SetChildLoader(nullptr);}voidCSSParserImpl::InitScanner(nsCSSScanner&aScanner,css::ErrorReporter&aReporter,nsIURI*aSheetURI,nsIURI*aBaseURI,nsIPrincipal*aSheetPrincipal){NS_PRECONDITION(!mHTMLMediaMode,"Bad initial state");NS_PRECONDITION(!mParsingCompoundProperty,"Bad initial state");NS_PRECONDITION(!mScanner,"already have scanner");mScanner=&aScanner;mReporter=&aReporter;mScanner->SetErrorReporter(mReporter);mBaseURI=aBaseURI;mSheetURI=aSheetURI;mSheetPrincipal=aSheetPrincipal;mHavePushBack=false;}voidCSSParserImpl::ReleaseScanner(){mScanner=nullptr;mReporter=nullptr;mBaseURI=nullptr;mSheetURI=nullptr;mSheetPrincipal=nullptr;}nsresultCSSParserImpl::ParseSheet(constnsAString&aInput,nsIURI*aSheetURI,nsIURI*aBaseURI,nsIPrincipal*aSheetPrincipal,uint32_taLineNumber,boolaAllowUnsafeRules){NS_PRECONDITION(aSheetPrincipal,"Must have principal here!");NS_PRECONDITION(aBaseURI,"need base URI");NS_PRECONDITION(aSheetURI,"need sheet URI");NS_PRECONDITION(mSheet,"Must have sheet to parse into");NS_ENSURE_STATE(mSheet);#ifdef DEBUGnsIURI*uri=mSheet->GetSheetURI();boolequal;NS_ASSERTION(NS_SUCCEEDED(aSheetURI->Equals(uri,&equal))&&equal,"Sheet URI does not match passed URI");NS_ASSERTION(NS_SUCCEEDED(mSheet->Principal()->Equals(aSheetPrincipal,&equal))&&equal,"Sheet principal does not match passed principal");#endifnsCSSScannerscanner(aInput,aLineNumber);css::ErrorReporterreporter(scanner,mSheet,mChildLoader,aSheetURI);InitScanner(scanner,reporter,aSheetURI,aBaseURI,aSheetPrincipal);int32_truleCount=mSheet->StyleRuleCount();if(0<ruleCount){css::Rule*lastRule=nullptr;mSheet->GetStyleRuleAt(ruleCount-1,lastRule);if(lastRule){switch(lastRule->GetType()){casecss::Rule::CHARSET_RULE:casecss::Rule::IMPORT_RULE:mSection=eCSSSection_Import;break;casecss::Rule::NAMESPACE_RULE:mSection=eCSSSection_NameSpace;break;default:mSection=eCSSSection_General;break;}NS_RELEASE(lastRule);}}else{mSection=eCSSSection_Charset;// sheet is empty, any rules are fair}mUnsafeRulesEnabled=aAllowUnsafeRules;nsCSSToken*tk=&mToken;for(;;){// Get next non-whitespace tokenif(!GetToken(true)){OUTPUT_ERROR();break;}if(eCSSToken_HTMLComment==tk->mType){continue;// legal here only}if(eCSSToken_AtKeyword==tk->mType){ParseAtRule(AppendRuleToSheet,this,false);continue;}UngetToken();if(ParseRuleSet(AppendRuleToSheet,this)){mSection=eCSSSection_General;}}ReleaseScanner();mUnsafeRulesEnabled=false;// XXX check for low level errorsreturnNS_OK;}/** * Determines whether the identifier contained in the given string is a * vendor-specific identifier, as described in CSS 2.1 section 4.1.2.1. */staticboolNonMozillaVendorIdentifier(constnsAString&ident){return(ident.First()==PRUnichar('-')&&!StringBeginsWith(ident,NS_LITERAL_STRING("-moz-")))||ident.First()==PRUnichar('_');}nsresultCSSParserImpl::ParseStyleAttribute(constnsAString&aAttributeValue,nsIURI*aDocURI,nsIURI*aBaseURI,nsIPrincipal*aNodePrincipal,css::StyleRule**aResult){NS_PRECONDITION(aNodePrincipal,"Must have principal here!");NS_PRECONDITION(aBaseURI,"need base URI");// XXX line number?nsCSSScannerscanner(aAttributeValue,0);css::ErrorReporterreporter(scanner,mSheet,mChildLoader,aDocURI);InitScanner(scanner,reporter,aDocURI,aBaseURI,aNodePrincipal);mSection=eCSSSection_General;// In quirks mode, allow style declarations to have braces or not// (bug 99554).boolhaveBraces;if(mNavQuirkMode&&GetToken(true)){haveBraces=eCSSToken_Symbol==mToken.mType&&'{'==mToken.mSymbol;UngetToken();}else{haveBraces=false;}uint32_tparseFlags=eParseDeclaration_AllowImportant;if(haveBraces){parseFlags|=eParseDeclaration_InBraces;}css::Declaration*declaration=ParseDeclarationBlock(parseFlags);if(declaration){// Create a style rule for the declarationNS_ADDREF(*aResult=newcss::StyleRule(nullptr,declaration));}else{*aResult=nullptr;}ReleaseScanner();// XXX check for low level errorsreturnNS_OK;}nsresultCSSParserImpl::ParseDeclarations(constnsAString&aBuffer,nsIURI*aSheetURI,nsIURI*aBaseURI,nsIPrincipal*aSheetPrincipal,css::Declaration*aDeclaration,bool*aChanged){*aChanged=false;NS_PRECONDITION(aSheetPrincipal,"Must have principal here!");nsCSSScannerscanner(aBuffer,0);css::ErrorReporterreporter(scanner,mSheet,mChildLoader,aSheetURI);InitScanner(scanner,reporter,aSheetURI,aBaseURI,aSheetPrincipal);mSection=eCSSSection_General;mData.AssertInitialState();aDeclaration->ClearData();// We could check if it was already empty, but...*aChanged=true;for(;;){// If we cleared the old decl, then we want to be calling// ValueAppended as we parse.if(!ParseDeclaration(aDeclaration,eParseDeclaration_AllowImportant,true,aChanged)){if(!SkipDeclaration(false)){break;}}}aDeclaration->CompressFrom(&mData);ReleaseScanner();returnNS_OK;}nsresultCSSParserImpl::ParseRule(constnsAString&aRule,nsIURI*aSheetURI,nsIURI*aBaseURI,nsIPrincipal*aSheetPrincipal,css::Rule**aResult){NS_PRECONDITION(aSheetPrincipal,"Must have principal here!");NS_PRECONDITION(aBaseURI,"need base URI");*aResult=nullptr;nsCSSScannerscanner(aRule,0);css::ErrorReporterreporter(scanner,mSheet,mChildLoader,aSheetURI);InitScanner(scanner,reporter,aSheetURI,aBaseURI,aSheetPrincipal);mSection=eCSSSection_Charset;// callers are responsible for rejecting invalid rules.nsCSSToken*tk=&mToken;// Get first non-whitespace tokennsresultrv=NS_OK;if(!GetToken(true)){REPORT_UNEXPECTED(PEParseRuleWSOnly);OUTPUT_ERROR();rv=NS_ERROR_DOM_SYNTAX_ERR;}else{if(eCSSToken_AtKeyword==tk->mType){// FIXME: perhaps aInsideBlock should be true when we are?ParseAtRule(AssignRuleToPointer,aResult,false);}else{UngetToken();ParseRuleSet(AssignRuleToPointer,aResult);}if(*aResult&&GetToken(true)){// garbage after ruleREPORT_UNEXPECTED_TOKEN(PERuleTrailing);NS_RELEASE(*aResult);}if(!*aResult){rv=NS_ERROR_DOM_SYNTAX_ERR;OUTPUT_ERROR();}}ReleaseScanner();returnrv;}// See Bug 723197#ifdef _MSC_VER#pragma optimize( "", off )#endifnsresultCSSParserImpl::ParseProperty(constnsCSSPropertyaPropID,constnsAString&aPropValue,nsIURI*aSheetURI,nsIURI*aBaseURI,nsIPrincipal*aSheetPrincipal,css::Declaration*aDeclaration,bool*aChanged,boolaIsImportant,boolaIsSVGMode){NS_PRECONDITION(aSheetPrincipal,"Must have principal here!");NS_PRECONDITION(aBaseURI,"need base URI");NS_PRECONDITION(aDeclaration,"Need declaration to parse into!");mData.AssertInitialState();mTempData.AssertInitialState();aDeclaration->AssertMutable();nsCSSScannerscanner(aPropValue,0);css::ErrorReporterreporter(scanner,mSheet,mChildLoader,aSheetURI);InitScanner(scanner,reporter,aSheetURI,aBaseURI,aSheetPrincipal);mSection=eCSSSection_General;scanner.SetSVGMode(aIsSVGMode);*aChanged=false;// Check for unknown or preffed off propertiesif(eCSSProperty_UNKNOWN==aPropID||!nsCSSProps::IsEnabled(aPropID)){NS_ConvertASCIItoUTF16propName(nsCSSProps::GetStringValue(aPropID));REPORT_UNEXPECTED_P(PEUnknownProperty,propName);REPORT_UNEXPECTED(PEDeclDropped);OUTPUT_ERROR();ReleaseScanner();returnNS_OK;}boolparsedOK=ParseProperty(aPropID);// We should now be at EOFif(parsedOK&&GetToken(true)){REPORT_UNEXPECTED_TOKEN(PEExpectEndValue);parsedOK=false;}if(!parsedOK){NS_ConvertASCIItoUTF16propName(nsCSSProps::GetStringValue(aPropID));REPORT_UNEXPECTED_P(PEValueParsingError,propName);REPORT_UNEXPECTED(PEDeclDropped);OUTPUT_ERROR();mTempData.ClearProperty(aPropID);}else{// We know we don't need to force a ValueAppended call for the new// value. So if we are not processing a shorthand, and there's// already a value for this property in the declaration at the// same importance level, then we can just copy our parsed value// directly into the declaration without going through the whole// expand/compress thing.if(!aDeclaration->TryReplaceValue(aPropID,aIsImportant,mTempData,aChanged)){// Do it the slow wayaDeclaration->ExpandTo(&mData);*aChanged=mData.TransferFromBlock(mTempData,aPropID,aIsImportant,true,false,aDeclaration);aDeclaration->CompressFrom(&mData);}CLEAR_ERROR();}mTempData.AssertInitialState();ReleaseScanner();returnNS_OK;}#ifdef _MSC_VER#pragma optimize( "", on )#endifnsresultCSSParserImpl::ParseMediaList(constnsSubstring&aBuffer,nsIURI*aURI,// for error reportinguint32_taLineNumber,// for error reportingnsMediaList*aMediaList,boolaHTMLMode){// XXX Are there cases where the caller wants to keep what it already// has in case of parser error? If GatherMedia ever changes to return// a value other than true, we probably should avoid modifying aMediaList.aMediaList->Clear();// fake base URI since media lists don't have URIs in themnsCSSScannerscanner(aBuffer,aLineNumber);css::ErrorReporterreporter(scanner,mSheet,mChildLoader,aURI);InitScanner(scanner,reporter,aURI,aURI,nullptr);mHTMLMediaMode=aHTMLMode;// XXXldb We need to make the scanner not skip CSS comments! (Or// should we?)// For aHTMLMode, we used to follow the parsing rules in// http://www.w3.org/TR/1999/REC-html401-19991224/types.html#type-media-descriptors// which wouldn't work for media queries since they remove all but the// first word. However, they're changed in// http://www.whatwg.org/specs/web-apps/current-work/multipage/section-document.html#media2// (as of 2008-05-29) which says that the media attribute just points// to a media query. (The main substative difference is the relative// precedence of commas and paretheses.)DebugOnly<bool>parsedOK=GatherMedia(aMediaList,false);NS_ASSERTION(parsedOK,"GatherMedia returned false; we probably want to avoid ""trashing aMediaList");CLEAR_ERROR();ReleaseScanner();mHTMLMediaMode=false;returnNS_OK;}boolCSSParserImpl::ParseColorString(constnsSubstring&aBuffer,nsIURI*aURI,// for error reportinguint32_taLineNumber,// for error reportingnsCSSValue&aValue){nsCSSScannerscanner(aBuffer,aLineNumber);css::ErrorReporterreporter(scanner,mSheet,mChildLoader,aURI);InitScanner(scanner,reporter,aURI,aURI,nullptr);// Parse a color, and check that there's nothing else after it.boolcolorParsed=ParseColor(aValue)&&!GetToken(true);OUTPUT_ERROR();ReleaseScanner();returncolorParsed;}nsresultCSSParserImpl::ParseSelectorString(constnsSubstring&aSelectorString,nsIURI*aURI,// for error reportinguint32_taLineNumber,// for error reportingnsCSSSelectorList**aSelectorList){nsCSSScannerscanner(aSelectorString,aLineNumber);css::ErrorReporterreporter(scanner,mSheet,mChildLoader,aURI);InitScanner(scanner,reporter,aURI,aURI,nullptr);boolsuccess=ParseSelectorList(*aSelectorList,PRUnichar(0));// We deliberately do not call OUTPUT_ERROR here, because all our// callers map a failure return to a JS exception, and if that JS// exception is caught, people don't want to see parser diagnostics;// see e.g. http://bugs.jquery.com/ticket/7535// It would be nice to be able to save the parser diagnostics into// the exception, so that if it _isn't_ caught we can report them// along with the usual uncaught-exception message, but we don't// have any way to do that at present; see bug 631621.CLEAR_ERROR();ReleaseScanner();if(success){NS_ASSERTION(*aSelectorList,"Should have list!");returnNS_OK;}NS_ASSERTION(!*aSelectorList,"Shouldn't have list!");returnNS_ERROR_DOM_SYNTAX_ERR;}already_AddRefed<nsCSSKeyframeRule>CSSParserImpl::ParseKeyframeRule(constnsSubstring&aBuffer,nsIURI*aURI,uint32_taLineNumber){nsCSSScannerscanner(aBuffer,aLineNumber);css::ErrorReporterreporter(scanner,mSheet,mChildLoader,aURI);InitScanner(scanner,reporter,aURI,aURI,nullptr);nsRefPtr<nsCSSKeyframeRule>result=ParseKeyframeRule();if(GetToken(true)){// extra garbage at the endresult=nullptr;}OUTPUT_ERROR();ReleaseScanner();returnresult.forget();}boolCSSParserImpl::ParseKeyframeSelectorString(constnsSubstring&aSelectorString,nsIURI*aURI,// for error reportinguint32_taLineNumber,// for error reportingInfallibleTArray<float>&aSelectorList){NS_ABORT_IF_FALSE(aSelectorList.IsEmpty(),"given list should start empty");nsCSSScannerscanner(aSelectorString,aLineNumber);css::ErrorReporterreporter(scanner,mSheet,mChildLoader,aURI);InitScanner(scanner,reporter,aURI,aURI,nullptr);boolsuccess=ParseKeyframeSelectorList(aSelectorList)&&// must consume entire input string!GetToken(true);OUTPUT_ERROR();ReleaseScanner();if(success){NS_ASSERTION(!aSelectorList.IsEmpty(),"should not be empty");}else{aSelectorList.Clear();}returnsuccess;}boolCSSParserImpl::EvaluateSupportsDeclaration(constnsAString&aProperty,constnsAString&aValue,nsIURI*aDocURL,nsIURI*aBaseURL,nsIPrincipal*aDocPrincipal){nsCSSPropertypropID=nsCSSProps::LookupProperty(aProperty,nsCSSProps::eEnabled);if(propID==eCSSProperty_UNKNOWN){returnfalse;}nsCSSScannerscanner(aValue,0);css::ErrorReporterreporter(scanner,mSheet,mChildLoader,aDocURL);InitScanner(scanner,reporter,aDocURL,aBaseURL,aDocPrincipal);nsAutoSuppressErrorssuppressErrors(this);boolparsedOK=ParseProperty(propID)&&!GetToken(true);CLEAR_ERROR();ReleaseScanner();mTempData.ClearProperty(propID);mTempData.AssertInitialState();returnparsedOK;}boolCSSParserImpl::EvaluateSupportsCondition(constnsAString&aDeclaration,nsIURI*aDocURL,nsIURI*aBaseURL,nsIPrincipal*aDocPrincipal){nsCSSScannerscanner(aDeclaration,0);css::ErrorReporterreporter(scanner,mSheet,mChildLoader,aDocURL);InitScanner(scanner,reporter,aDocURL,aBaseURL,aDocPrincipal);nsAutoSuppressErrorssuppressErrors(this);boolconditionMet;boolparsedOK=ParseSupportsCondition(conditionMet)&&!GetToken(true);CLEAR_ERROR();ReleaseScanner();returnparsedOK&&conditionMet;}//----------------------------------------------------------------------boolCSSParserImpl::GetToken(boolaSkipWS){if(mHavePushBack){mHavePushBack=false;if(!aSkipWS||mToken.mType!=eCSSToken_Whitespace){returntrue;}}returnmScanner->Next(mToken,aSkipWS);}voidCSSParserImpl::UngetToken(){NS_PRECONDITION(!mHavePushBack,"double pushback");mHavePushBack=true;}boolCSSParserImpl::ExpectSymbol(PRUnicharaSymbol,boolaSkipWS){if(!GetToken(aSkipWS)){// CSS2.1 specifies that all "open constructs" are to be closed at// EOF. It simplifies higher layers if we claim to have found an// ), ], }, or ; if we encounter EOF while looking for one of them.// Do still issue a diagnostic, to aid debugging.if(aSymbol==')'||aSymbol==']'||aSymbol=='}'||aSymbol==';'){REPORT_UNEXPECTED_EOF_CHAR(aSymbol);returntrue;}elsereturnfalse;}if(mToken.IsSymbol(aSymbol)){returntrue;}UngetToken();returnfalse;}// Checks to see if we're at the end of a property. If an error occurs during// the check, does not signal a parse error.boolCSSParserImpl::CheckEndProperty(){if(!GetToken(true)){returntrue;// properties may end with eof}if((eCSSToken_Symbol==mToken.mType)&&((';'==mToken.mSymbol)||('!'==mToken.mSymbol)||('}'==mToken.mSymbol)||(')'==mToken.mSymbol))){// XXX need to verify that ! is only followed by "important [;|}]// XXX this requires a multi-token pushback bufferUngetToken();returntrue;}UngetToken();returnfalse;}// Checks if we're at the end of a property, raising an error if we're not.boolCSSParserImpl::ExpectEndProperty(){if(CheckEndProperty())returntrue;// If we're here, we read something incorrect, so we should report it.REPORT_UNEXPECTED_TOKEN(PEExpectEndValue);returnfalse;}// Parses the priority suffix on a property, which at present may be// either '!important' or nothing.CSSParserImpl::PriorityParsingStatusCSSParserImpl::ParsePriority(){if(!GetToken(true)){returnePriority_None;// properties may end with EOF}if(!mToken.IsSymbol('!')){UngetToken();returnePriority_None;// dunno what it is, but it's not a priority}if(!GetToken(true)){// EOF is not ok after !REPORT_UNEXPECTED_EOF(PEImportantEOF);returnePriority_Error;}if(mToken.mType!=eCSSToken_Ident||!mToken.mIdent.LowerCaseEqualsLiteral("important")){REPORT_UNEXPECTED_TOKEN(PEExpectedImportant);UngetToken();returnePriority_Error;}returnePriority_Important;}nsSubstring*CSSParserImpl::NextIdent(){// XXX Error reporting?if(!GetToken(true)){returnnullptr;}if(eCSSToken_Ident!=mToken.mType){UngetToken();returnnullptr;}return&mToken.mIdent;}boolCSSParserImpl::SkipAtRule(boolaInsideBlock){for(;;){if(!GetToken(true)){REPORT_UNEXPECTED_EOF(PESkipAtRuleEOF2);returnfalse;}if(eCSSToken_Symbol==mToken.mType){PRUnicharsymbol=mToken.mSymbol;if(symbol==';'){break;}if(aInsideBlock&&symbol=='}'){// The closing } doesn't belong to us.UngetToken();break;}if(symbol=='{'){SkipUntil('}');break;}elseif(symbol=='('){SkipUntil(')');}elseif(symbol=='['){SkipUntil(']');}}elseif(eCSSToken_Function==mToken.mType||eCSSToken_Bad_URL==mToken.mType){SkipUntil(')');}}returntrue;}boolCSSParserImpl::ParseAtRule(RuleAppendFuncaAppendFunc,void*aData,boolaInAtRule){nsCSSSectionnewSection;bool(CSSParserImpl::*parseFunc)(RuleAppendFunc,void*);if((mSection<=eCSSSection_Charset)&&(mToken.mIdent.LowerCaseEqualsLiteral("charset"))){parseFunc=&CSSParserImpl::ParseCharsetRule;newSection=eCSSSection_Import;// only one charset allowed}elseif((mSection<=eCSSSection_Import)&&mToken.mIdent.LowerCaseEqualsLiteral("import")){parseFunc=&CSSParserImpl::ParseImportRule;newSection=eCSSSection_Import;}elseif((mSection<=eCSSSection_NameSpace)&&mToken.mIdent.LowerCaseEqualsLiteral("namespace")){parseFunc=&CSSParserImpl::ParseNameSpaceRule;newSection=eCSSSection_NameSpace;}elseif(mToken.mIdent.LowerCaseEqualsLiteral("media")){parseFunc=&CSSParserImpl::ParseMediaRule;newSection=eCSSSection_General;}elseif(mToken.mIdent.LowerCaseEqualsLiteral("-moz-document")){parseFunc=&CSSParserImpl::ParseMozDocumentRule;newSection=eCSSSection_General;}elseif(mToken.mIdent.LowerCaseEqualsLiteral("font-face")){parseFunc=&CSSParserImpl::ParseFontFaceRule;newSection=eCSSSection_General;}elseif(mToken.mIdent.LowerCaseEqualsLiteral("page")){parseFunc=&CSSParserImpl::ParsePageRule;newSection=eCSSSection_General;}elseif(mToken.mIdent.LowerCaseEqualsLiteral("-moz-keyframes")||mToken.mIdent.LowerCaseEqualsLiteral("keyframes")){parseFunc=&CSSParserImpl::ParseKeyframesRule;newSection=eCSSSection_General;}elseif(mToken.mIdent.LowerCaseEqualsLiteral("supports")&&CSSSupportsRule::PrefEnabled()){parseFunc=&CSSParserImpl::ParseSupportsRule;newSection=eCSSSection_General;}else{if(!NonMozillaVendorIdentifier(mToken.mIdent)){REPORT_UNEXPECTED_TOKEN(PEUnknownAtRule);OUTPUT_ERROR();}// Skip over unsupported at rule, don't advance sectionreturnSkipAtRule(aInAtRule);}// Inside of @-rules, only the rules that can occur anywhere// are allowed.boolunnestable=aInAtRule&&newSection!=eCSSSection_General;if(unnestable){REPORT_UNEXPECTED_TOKEN(PEGroupRuleNestedAtRule);}if(unnestable||!(this->*parseFunc)(aAppendFunc,aData)){// Skip over invalid at rule, don't advance sectionOUTPUT_ERROR();returnSkipAtRule(aInAtRule);}// Nested @-rules don't affect the top-level rule chain requirementif(!aInAtRule){mSection=newSection;}returntrue;}boolCSSParserImpl::ParseCharsetRule(RuleAppendFuncaAppendFunc,void*aData){if(!GetToken(true)){REPORT_UNEXPECTED_EOF(PECharsetRuleEOF);returnfalse;}if(eCSSToken_String!=mToken.mType){UngetToken();REPORT_UNEXPECTED_TOKEN(PECharsetRuleNotString);returnfalse;}nsAutoStringcharset=mToken.mIdent;if(!ExpectSymbol(';',true)){returnfalse;}nsRefPtr<css::CharsetRule>rule=newcss::CharsetRule(charset);(*aAppendFunc)(rule,aData);returntrue;}boolCSSParserImpl::ParseURLOrString(nsString&aURL){if(!GetToken(true)){returnfalse;}if(eCSSToken_String==mToken.mType||eCSSToken_URL==mToken.mType){aURL=mToken.mIdent;returntrue;}UngetToken();returnfalse;}boolCSSParserImpl::ParseMediaQuery(boolaInAtRule,nsMediaQuery**aQuery,bool*aHitStop){*aQuery=nullptr;*aHitStop=false;// "If the comma-separated list is the empty list it is assumed to// specify the media query 'all'." (css3-mediaqueries, section// "Media Queries")if(!GetToken(true)){*aHitStop=true;// expected termination by EOFif(!aInAtRule)returntrue;// unexpected termination by EOFREPORT_UNEXPECTED_EOF(PEGatherMediaEOF);returntrue;}if(eCSSToken_Symbol==mToken.mType&&aInAtRule&&(mToken.mSymbol==';'||mToken.mSymbol=='{'||mToken.mSymbol=='}')){*aHitStop=true;UngetToken();returntrue;}UngetToken();nsMediaQuery*query=newnsMediaQuery;*aQuery=query;if(ExpectSymbol('(',true)){// we got an expression without a media typeUngetToken();// so ParseMediaQueryExpression can handle itquery->SetType(nsGkAtoms::all);query->SetTypeOmitted();// Just parse the first expression here.if(!ParseMediaQueryExpression(query)){OUTPUT_ERROR();query->SetHadUnknownExpression();}}else{nsCOMPtr<nsIAtom>mediaType;boolgotNotOrOnly=false;for(;;){if(!GetToken(true)){REPORT_UNEXPECTED_EOF(PEGatherMediaEOF);returnfalse;}if(eCSSToken_Ident!=mToken.mType){REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotIdent);UngetToken();returnfalse;}// case insensitive from CSS - must be lower casednsContentUtils::ASCIIToLower(mToken.mIdent);mediaType=do_GetAtom(mToken.mIdent);if(!mediaType){NS_RUNTIMEABORT("do_GetAtom failed - out of memory?");}if(gotNotOrOnly||(mediaType!=nsGkAtoms::_not&&mediaType!=nsGkAtoms::only))break;gotNotOrOnly=true;if(mediaType==nsGkAtoms::_not)query->SetNegated();elsequery->SetHasOnly();}query->SetType(mediaType);}for(;;){if(!GetToken(true)){*aHitStop=true;// expected termination by EOFif(!aInAtRule)break;// unexpected termination by EOFREPORT_UNEXPECTED_EOF(PEGatherMediaEOF);break;}if(eCSSToken_Symbol==mToken.mType&&aInAtRule&&(mToken.mSymbol==';'||mToken.mSymbol=='{'||mToken.mSymbol=='}')){*aHitStop=true;UngetToken();break;}if(eCSSToken_Symbol==mToken.mType&&mToken.mSymbol==','){// Done with the expressions for this querybreak;}if(eCSSToken_Ident!=mToken.mType||!mToken.mIdent.LowerCaseEqualsLiteral("and")){REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotComma);UngetToken();returnfalse;}if(!ParseMediaQueryExpression(query)){OUTPUT_ERROR();query->SetHadUnknownExpression();}}returntrue;}// Returns false only when there is a low-level error in the scanner// (out-of-memory).boolCSSParserImpl::GatherMedia(nsMediaList*aMedia,boolaInAtRule){for(;;){nsAutoPtr<nsMediaQuery>query;boolhitStop;if(!ParseMediaQuery(aInAtRule,getter_Transfers(query),&hitStop)){NS_ASSERTION(!hitStop,"should return true when hit stop");OUTPUT_ERROR();if(query){query->SetHadUnknownExpression();}if(aInAtRule){constPRUnicharstopChars[]={PRUnichar(','),PRUnichar('{'),PRUnichar(';'),PRUnichar('}'),PRUnichar(0)};SkipUntilOneOf(stopChars);}else{SkipUntil(',');}// Rely on SkipUntilOneOf leaving mToken around as the last token read.if(mToken.mType==eCSSToken_Symbol&&aInAtRule&&(mToken.mSymbol=='{'||mToken.mSymbol==';'||mToken.mSymbol=='}')){UngetToken();hitStop=true;}}if(query){aMedia->AppendQuery(query);}if(hitStop){break;}}returntrue;}boolCSSParserImpl::ParseMediaQueryExpression(nsMediaQuery*aQuery){if(!ExpectSymbol('(',true)){REPORT_UNEXPECTED_TOKEN(PEMQExpectedExpressionStart);returnfalse;}if(!GetToken(true)){REPORT_UNEXPECTED_EOF(PEMQExpressionEOF);returnfalse;}if(eCSSToken_Ident!=mToken.mType){REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureName);UngetToken();SkipUntil(')');returnfalse;}nsMediaExpression*expr=aQuery->NewExpression();// case insensitive from CSS - must be lower casednsContentUtils::ASCIIToLower(mToken.mIdent);constPRUnichar*featureString;if(StringBeginsWith(mToken.mIdent,NS_LITERAL_STRING("min-"))){expr->mRange=nsMediaExpression::eMin;featureString=mToken.mIdent.get()+4;}elseif(StringBeginsWith(mToken.mIdent,NS_LITERAL_STRING("max-"))){expr->mRange=nsMediaExpression::eMax;featureString=mToken.mIdent.get()+4;}else{expr->mRange=nsMediaExpression::eEqual;featureString=mToken.mIdent.get();}nsCOMPtr<nsIAtom>mediaFeatureAtom=do_GetAtom(featureString);if(!mediaFeatureAtom){NS_RUNTIMEABORT("do_GetAtom failed - out of memory?");}constnsMediaFeature*feature=nsMediaFeatures::features;for(;feature->mName;++feature){if(*(feature->mName)==mediaFeatureAtom){break;}}if(!feature->mName||(expr->mRange!=nsMediaExpression::eEqual&&feature->mRangeType!=nsMediaFeature::eMinMaxAllowed)){REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureName);SkipUntil(')');returnfalse;}expr->mFeature=feature;if(!GetToken(true)||mToken.IsSymbol(')')){// Query expressions for any feature can be given without a value.// However, min/max prefixes are not allowed.if(expr->mRange!=nsMediaExpression::eEqual){REPORT_UNEXPECTED(PEMQNoMinMaxWithoutValue);returnfalse;}expr->mValue.Reset();returntrue;}if(!mToken.IsSymbol(':')){REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureNameEnd);UngetToken();SkipUntil(')');returnfalse;}boolrv;switch(feature->mValueType){casensMediaFeature::eLength:rv=ParseNonNegativeVariant(expr->mValue,VARIANT_LENGTH,nullptr);break;casensMediaFeature::eInteger:casensMediaFeature::eBoolInteger:rv=ParseNonNegativeVariant(expr->mValue,VARIANT_INTEGER,nullptr);// Enforce extra restrictions for eBoolIntegerif(rv&&feature->mValueType==nsMediaFeature::eBoolInteger&&expr->mValue.GetIntValue()>1)rv=false;break;casensMediaFeature::eFloat:rv=ParseNonNegativeVariant(expr->mValue,VARIANT_NUMBER,nullptr);break;casensMediaFeature::eIntRatio:{// Two integers separated by '/', with optional whitespace on// either side of the '/'.nsRefPtr<nsCSSValue::Array>a=nsCSSValue::Array::Create(2);expr->mValue.SetArrayValue(a,eCSSUnit_Array);// We don't bother with ParseNonNegativeVariant since we have to// check for != 0 as well; no need to worry about the UngetToken// since we're throwing out up to the next ')' anyway.rv=ParseVariant(a->Item(0),VARIANT_INTEGER,nullptr)&&a->Item(0).GetIntValue()>0&&ExpectSymbol('/',true)&&ParseVariant(a->Item(1),VARIANT_INTEGER,nullptr)&&a->Item(1).GetIntValue()>0;}break;casensMediaFeature::eResolution:rv=GetToken(true);if(!rv)break;rv=mToken.mType==eCSSToken_Dimension&&mToken.mNumber>0.0f;if(!rv){UngetToken();break;}// No worries about whether unitless zero is allowed, since the// value must be positive (and we checked that above).NS_ASSERTION(!mToken.mIdent.IsEmpty(),"unit lied");if(mToken.mIdent.LowerCaseEqualsLiteral("dpi")){expr->mValue.SetFloatValue(mToken.mNumber,eCSSUnit_Inch);}elseif(mToken.mIdent.LowerCaseEqualsLiteral("dppx")){expr->mValue.SetFloatValue(mToken.mNumber,eCSSUnit_Pixel);}elseif(mToken.mIdent.LowerCaseEqualsLiteral("dpcm")){expr->mValue.SetFloatValue(mToken.mNumber,eCSSUnit_Centimeter);}else{rv=false;}break;casensMediaFeature::eEnumerated:rv=ParseVariant(expr->mValue,VARIANT_KEYWORD,feature->mData.mKeywordTable);break;casensMediaFeature::eIdent:rv=ParseVariant(expr->mValue,VARIANT_IDENTIFIER,nullptr);break;}if(!rv||!ExpectSymbol(')',true)){REPORT_UNEXPECTED(PEMQExpectedFeatureValue);SkipUntil(')');returnfalse;}returntrue;}// Parse a CSS2 import rule: "@import STRING | URL [medium [, medium]]"boolCSSParserImpl::ParseImportRule(RuleAppendFuncaAppendFunc,void*aData){nsRefPtr<nsMediaList>media=newnsMediaList();nsAutoStringurl;if(!ParseURLOrString(url)){REPORT_UNEXPECTED_TOKEN(PEImportNotURI);returnfalse;}if(!ExpectSymbol(';',true)){if(!GatherMedia(media,true)||!ExpectSymbol(';',true)){REPORT_UNEXPECTED_TOKEN(PEImportUnexpected);// don't advance section, simply ignore invalid @importreturnfalse;}// Safe to assert this, since we ensured that there is something// other than the ';' coming after the @import's url() token.NS_ASSERTION(media->Count()!=0,"media list must be nonempty");}ProcessImport(url,media,aAppendFunc,aData);returntrue;}voidCSSParserImpl::ProcessImport(constnsString&aURLSpec,nsMediaList*aMedia,RuleAppendFuncaAppendFunc,void*aData){nsRefPtr<css::ImportRule>rule=newcss::ImportRule(aMedia,aURLSpec);(*aAppendFunc)(rule,aData);// Diagnose bad URIs even if we don't have a child loader.nsCOMPtr<nsIURI>url;// Charset will be deduced from mBaseURI, which is more or less correct.nsresultrv=NS_NewURI(getter_AddRefs(url),aURLSpec,nullptr,mBaseURI);if(NS_FAILED(rv)){if(rv==NS_ERROR_MALFORMED_URI){// import url is badREPORT_UNEXPECTED_P(PEImportBadURI,aURLSpec);OUTPUT_ERROR();}return;}if(mChildLoader){mChildLoader->LoadChildSheet(mSheet,url,aMedia,rule);}}// Parse the {} part of an @media or @-moz-document rule.boolCSSParserImpl::ParseGroupRule(css::GroupRule*aRule,RuleAppendFuncaAppendFunc,void*aData){// XXXbz this could use better error reporting throughout the methodif(!ExpectSymbol('{',true)){returnfalse;}// push rule on stack, loop over childrenPushGroup(aRule);nsCSSSectionholdSection=mSection;mSection=eCSSSection_General;for(;;){// Get next non-whitespace tokenif(!GetToken(true)){REPORT_UNEXPECTED_EOF(PEGroupRuleEOF2);break;}if(mToken.IsSymbol('}')){// done!UngetToken();break;}if(eCSSToken_AtKeyword==mToken.mType){// Parse for nested rulesParseAtRule(aAppendFunc,aData,true);continue;}UngetToken();ParseRuleSet(AppendRuleToSheet,this,true);}PopGroup();if(!ExpectSymbol('}',true)){mSection=holdSection;returnfalse;}(*aAppendFunc)(aRule,aData);returntrue;}// Parse a CSS2 media rule: "@media medium [, medium] { ... }"boolCSSParserImpl::ParseMediaRule(RuleAppendFuncaAppendFunc,void*aData){nsRefPtr<nsMediaList>media=newnsMediaList();if(GatherMedia(media,true)){// XXXbz this could use better error reporting throughout the methodnsRefPtr<css::MediaRule>rule=newcss::MediaRule();// Append first, so when we do SetMedia() the rule// knows what its stylesheet is.if(ParseGroupRule(rule,aAppendFunc,aData)){rule->SetMedia(media);returntrue;}}returnfalse;}// Parse a @-moz-document rule. This is like an @media rule, but instead// of a medium it has a nonempty list of items where each item is either// url(), url-prefix(), or domain().boolCSSParserImpl::ParseMozDocumentRule(RuleAppendFuncaAppendFunc,void*aData){css::DocumentRule::URL*urls=nullptr;css::DocumentRule::URL**next=&urls;do{if(!GetToken(true)){REPORT_UNEXPECTED_EOF(PEMozDocRuleEOF);deleteurls;returnfalse;}if(!(eCSSToken_URL==mToken.mType||(eCSSToken_Function==mToken.mType&&(mToken.mIdent.LowerCaseEqualsLiteral("url-prefix")||mToken.mIdent.LowerCaseEqualsLiteral("domain")||mToken.mIdent.LowerCaseEqualsLiteral("regexp"))))){REPORT_UNEXPECTED_TOKEN(PEMozDocRuleBadFunc);UngetToken();deleteurls;returnfalse;}css::DocumentRule::URL*cur=*next=newcss::DocumentRule::URL;next=&cur->next;if(mToken.mType==eCSSToken_URL){cur->func=css::DocumentRule::eURL;CopyUTF16toUTF8(mToken.mIdent,cur->url);}elseif(mToken.mIdent.LowerCaseEqualsLiteral("regexp")){// regexp() is different from url-prefix() and domain() (but// probably the way they *should* have been* in that it requires a// string argument, and doesn't try to behave like url().cur->func=css::DocumentRule::eRegExp;GetToken(true);// copy before we know it's valid (but before ExpectSymbol changes// mToken.mIdent)CopyUTF16toUTF8(mToken.mIdent,cur->url);if(eCSSToken_String!=mToken.mType||!ExpectSymbol(')',true)){REPORT_UNEXPECTED_TOKEN(PEMozDocRuleNotString);SkipUntil(')');deleteurls;returnfalse;}}else{if(mToken.mIdent.LowerCaseEqualsLiteral("url-prefix")){cur->func=css::DocumentRule::eURLPrefix;}elseif(mToken.mIdent.LowerCaseEqualsLiteral("domain")){cur->func=css::DocumentRule::eDomain;}NS_ASSERTION(!mHavePushBack,"mustn't have pushback at this point");if(!mScanner->NextURL(mToken)||mToken.mType!=eCSSToken_URL){REPORT_UNEXPECTED_TOKEN(PEMozDocRuleNotURI);SkipUntil(')');deleteurls;returnfalse;}// We could try to make the URL (as long as it's not domain())// canonical and absolute with NS_NewURI and GetSpec, but I'm// inclined to think we shouldn't.CopyUTF16toUTF8(mToken.mIdent,cur->url);}}while(ExpectSymbol(',',true));nsRefPtr<css::DocumentRule>rule=newcss::DocumentRule();rule->SetURLs(urls);returnParseGroupRule(rule,aAppendFunc,aData);}// Parse a CSS3 namespace rule: "@namespace [prefix] STRING | URL;"boolCSSParserImpl::ParseNameSpaceRule(RuleAppendFuncaAppendFunc,void*aData){if(!GetToken(true)){REPORT_UNEXPECTED_EOF(PEAtNSPrefixEOF);returnfalse;}nsAutoStringprefix;nsAutoStringurl;if(eCSSToken_Ident==mToken.mType){prefix=mToken.mIdent;// user-specified identifiers are case-sensitive (bug 416106)}else{UngetToken();}if(!ParseURLOrString(url)||!ExpectSymbol(';',true)){if(mHavePushBack){REPORT_UNEXPECTED_TOKEN(PEAtNSUnexpected);}else{REPORT_UNEXPECTED_EOF(PEAtNSURIEOF);}returnfalse;}ProcessNameSpace(prefix,url,aAppendFunc,aData);returntrue;}voidCSSParserImpl::ProcessNameSpace(constnsString&aPrefix,constnsString&aURLSpec,RuleAppendFuncaAppendFunc,void*aData){nsCOMPtr<nsIAtom>prefix;if(!aPrefix.IsEmpty()){prefix=do_GetAtom(aPrefix);if(!prefix){NS_RUNTIMEABORT("do_GetAtom failed - out of memory?");}}nsRefPtr<css::NameSpaceRule>rule=newcss::NameSpaceRule(prefix,aURLSpec);(*aAppendFunc)(rule,aData);// If this was the first namespace rule encountered, it will trigger// creation of a namespace map.if(!mNameSpaceMap){mNameSpaceMap=mSheet->GetNameSpaceMap();}}// font-face-rule: '@font-face' '{' font-description '}'// font-description: font-descriptor+boolCSSParserImpl::ParseFontFaceRule(RuleAppendFuncaAppendFunc,void*aData){if(!ExpectSymbol('{',true)){REPORT_UNEXPECTED_TOKEN(PEBadFontBlockStart);returnfalse;}nsRefPtr<nsCSSFontFaceRule>rule(newnsCSSFontFaceRule());for(;;){if(!GetToken(true)){REPORT_UNEXPECTED_EOF(PEFontFaceEOF);break;}if(mToken.IsSymbol('}')){// done!UngetToken();break;}// ignore extra semicolonsif(mToken.IsSymbol(';'))continue;if(!ParseFontDescriptor(rule)){REPORT_UNEXPECTED(PEDeclSkipped);OUTPUT_ERROR();if(!SkipDeclaration(true))break;}}if(!ExpectSymbol('}',true)){REPORT_UNEXPECTED_TOKEN(PEBadFontBlockEnd);returnfalse;}(*aAppendFunc)(rule,aData);returntrue;}// font-descriptor: font-family-desc// | font-style-desc// | font-weight-desc// | font-stretch-desc// | font-src-desc// | unicode-range-desc//// All font-*-desc productions follow the pattern// IDENT ':' value ';'//// On entry to this function, mToken is the IDENT.boolCSSParserImpl::ParseFontDescriptor(nsCSSFontFaceRule*aRule){if(eCSSToken_Ident!=mToken.mType){REPORT_UNEXPECTED_TOKEN(PEFontDescExpected);returnfalse;}nsStringdescName=mToken.mIdent;if(!ExpectSymbol(':',true)){REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon);OUTPUT_ERROR();returnfalse;}nsCSSFontDescdescID=nsCSSProps::LookupFontDesc(descName);nsCSSValuevalue;if(descID==eCSSFontDesc_UNKNOWN){if(NonMozillaVendorIdentifier(descName)){// silently skip other vendors' extensionsSkipDeclaration(true);returntrue;}else{REPORT_UNEXPECTED_P(PEUnknownFontDesc,descName);returnfalse;}}if(!ParseFontDescriptorValue(descID,value)){REPORT_UNEXPECTED_P(PEValueParsingError,descName);returnfalse;}if(!ExpectEndProperty())returnfalse;aRule->SetDesc(descID,value);returntrue;}boolCSSParserImpl::ParseKeyframesRule(RuleAppendFuncaAppendFunc,void*aData){if(!GetToken(true)){REPORT_UNEXPECTED_EOF(PEKeyframeNameEOF);returnfalse;}if(mToken.mType!=eCSSToken_Ident){REPORT_UNEXPECTED_TOKEN(PEKeyframeBadName);UngetToken();returnfalse;}nsStringname(mToken.mIdent);if(!ExpectSymbol('{',true)){REPORT_UNEXPECTED_TOKEN(PEKeyframeBrace);returnfalse;}nsRefPtr<nsCSSKeyframesRule>rule=newnsCSSKeyframesRule(name);while(!ExpectSymbol('}',true)){nsRefPtr<nsCSSKeyframeRule>kid=ParseKeyframeRule();if(kid){rule->AppendStyleRule(kid);}else{OUTPUT_ERROR();SkipRuleSet(true);}}(*aAppendFunc)(rule,aData);returntrue;}boolCSSParserImpl::ParsePageRule(RuleAppendFuncaAppendFunc,void*aData){// TODO: There can be page selectors after @page such as ":first", ":left".uint32_tparseFlags=eParseDeclaration_InBraces|eParseDeclaration_AllowImportant;// Forbid viewport units in @page rules. See bug 811391.NS_ABORT_IF_FALSE(mViewportUnitsEnabled,"Viewport units should be enabled outside of @page rules.");mViewportUnitsEnabled=false;nsAutoPtr<css::Declaration>declaration(ParseDeclarationBlock(parseFlags,eCSSContext_Page));mViewportUnitsEnabled=true;if(!declaration){returnfalse;}// Takes ownership of declaration.nsRefPtr<nsCSSPageRule>rule=newnsCSSPageRule(declaration);(*aAppendFunc)(rule,aData);returntrue;}already_AddRefed<nsCSSKeyframeRule>CSSParserImpl::ParseKeyframeRule(){InfallibleTArray<float>selectorList;if(!ParseKeyframeSelectorList(selectorList)){REPORT_UNEXPECTED(PEBadSelectorKeyframeRuleIgnored);returnnullptr;}// Ignore !important in keyframe rulesuint32_tparseFlags=eParseDeclaration_InBraces;nsAutoPtr<css::Declaration>declaration(ParseDeclarationBlock(parseFlags));if(!declaration){returnnullptr;}// Takes ownership of declaration, and steals contents of selectorList.nsRefPtr<nsCSSKeyframeRule>rule=newnsCSSKeyframeRule(selectorList,declaration);returnrule.forget();}boolCSSParserImpl::ParseKeyframeSelectorList(InfallibleTArray<float>&aSelectorList){for(;;){if(!GetToken(true)){// The first time through the loop, this means we got an empty// list. Otherwise, it means we have a trailing comma.returnfalse;}floatvalue;switch(mToken.mType){caseeCSSToken_Percentage:value=mToken.mNumber;break;caseeCSSToken_Ident:if(mToken.mIdent.LowerCaseEqualsLiteral("from")){value=0.0f;break;}if(mToken.mIdent.LowerCaseEqualsLiteral("to")){value=1.0f;break;}// fall throughdefault:UngetToken();// The first time through the loop, this means we got an empty// list. Otherwise, it means we have a trailing comma.returnfalse;}aSelectorList.AppendElement(value);if(!ExpectSymbol(',',true)){returntrue;}}}// supports_rule// : "@supports" supports_condition group_rule_body// ;boolCSSParserImpl::ParseSupportsRule(RuleAppendFuncaAppendFunc,void*aProcessData){boolconditionMet=false;nsStringcondition;mScanner->StartRecording();boolparsed=ParseSupportsCondition(conditionMet);if(!parsed){mScanner->StopRecording();returnfalse;}if(!ExpectSymbol('{',true)){REPORT_UNEXPECTED_TOKEN(PESupportsGroupRuleStart);mScanner->StopRecording();returnfalse;}UngetToken();mScanner->StopRecording(condition);// Remove the "{" that would follow the condition.if(condition.Length()!=0){condition.Truncate(condition.Length()-1);}// Remove spaces from the start and end of the recorded supports condition.condition.Trim(" ",true,true,false);// Record whether we are in a failing @supports, so that property parse// errors don't get reported.nsAutoFailingSupportsRulefailing(this,conditionMet);nsRefPtr<css::GroupRule>rule=newCSSSupportsRule(conditionMet,condition);returnParseGroupRule(rule,aAppendFunc,aProcessData);}// supports_condition// : supports_condition_in_parens supports_condition_terms// | supports_condition_negation// ;boolCSSParserImpl::ParseSupportsCondition(bool&aConditionMet){if(!GetToken(true)){REPORT_UNEXPECTED_EOF(PESupportsConditionStartEOF2);returnfalse;}UngetToken();if(mToken.IsSymbol('(')||mToken.mType==eCSSToken_Function||mToken.mType==eCSSToken_URL||mToken.mType==eCSSToken_Bad_URL){returnParseSupportsConditionInParens(aConditionMet)&&ParseSupportsConditionTerms(aConditionMet);}if(mToken.mType==eCSSToken_Ident&&mToken.mIdent.LowerCaseEqualsLiteral("not")){returnParseSupportsConditionNegation(aConditionMet);}REPORT_UNEXPECTED_TOKEN(PESupportsConditionExpectedStart);returnfalse;}// supports_condition_negation// : 'not' S+ supports_condition_in_parens// ;boolCSSParserImpl::ParseSupportsConditionNegation(bool&aConditionMet){if(!GetToken(true)){REPORT_UNEXPECTED_EOF(PESupportsConditionNotEOF);returnfalse;}if(mToken.mType!=eCSSToken_Ident||!mToken.mIdent.LowerCaseEqualsLiteral("not")){REPORT_UNEXPECTED_TOKEN(PESupportsConditionExpectedNot);returnfalse;}if(!RequireWhitespace()){REPORT_UNEXPECTED(PESupportsWhitespaceRequired);returnfalse;}if(ParseSupportsConditionInParens(aConditionMet)){aConditionMet=!aConditionMet;returntrue;}returnfalse;}// supports_condition_in_parens// : '(' S* supports_condition_in_parens_inside_parens ')' S*// | general_enclosed// ;boolCSSParserImpl::ParseSupportsConditionInParens(bool&aConditionMet){if(!GetToken(true)){REPORT_UNEXPECTED_EOF(PESupportsConditionInParensStartEOF);returnfalse;}if(mToken.mType==eCSSToken_URL){aConditionMet=false;returntrue;}if(mToken.mType==eCSSToken_Function||mToken.mType==eCSSToken_Bad_URL){if(!SkipUntil(')')){REPORT_UNEXPECTED_EOF(PESupportsConditionInParensEOF);returnfalse;}aConditionMet=false;returntrue;}if(!mToken.IsSymbol('(')){REPORT_UNEXPECTED_TOKEN(PESupportsConditionExpectedOpenParenOrFunction);UngetToken();returnfalse;}if(!ParseSupportsConditionInParensInsideParens(aConditionMet)){if(!SkipUntil(')')){REPORT_UNEXPECTED_EOF(PESupportsConditionInParensEOF);returnfalse;}aConditionMet=false;returntrue;}if(!(ExpectSymbol(')',true))){REPORT_UNEXPECTED_TOKEN(PESupportsConditionExpectedCloseParen);SkipUntil(')');returnfalse;}returntrue;}// supports_condition_in_parens_inside_parens// : core_declaration// | supports_condition_negation// | supports_condition_in_parens supports_condition_terms// ;boolCSSParserImpl::ParseSupportsConditionInParensInsideParens(bool&aConditionMet){if(!GetToken(true)){returnfalse;}if(mToken.mType==eCSSToken_Ident){if(!mToken.mIdent.LowerCaseEqualsLiteral("not")){nsAutoStringpropertyName=mToken.mIdent;if(!ExpectSymbol(':',true)){returnfalse;}if(ExpectSymbol(')',true)){UngetToken();returnfalse;}nsCSSPropertypropID=nsCSSProps::LookupProperty(propertyName,nsCSSProps::eEnabled);if(propID==eCSSProperty_UNKNOWN){aConditionMet=false;SkipUntil(')');UngetToken();}else{aConditionMet=ParseProperty(propID)&&ParsePriority()!=ePriority_Error;if(!aConditionMet){SkipUntil(')');UngetToken();}mTempData.ClearProperty(propID);mTempData.AssertInitialState();}returntrue;}UngetToken();returnParseSupportsConditionNegation(aConditionMet);}UngetToken();returnParseSupportsConditionInParens(aConditionMet)&&ParseSupportsConditionTerms(aConditionMet);}// supports_condition_terms// : S+ 'and' supports_condition_terms_after_operator('and')// | S+ 'or' supports_condition_terms_after_operator('or')// |// ;boolCSSParserImpl::ParseSupportsConditionTerms(bool&aConditionMet){if(!RequireWhitespace()||!GetToken(false)){returntrue;}if(mToken.mType!=eCSSToken_Ident){UngetToken();returntrue;}if(mToken.mIdent.LowerCaseEqualsLiteral("and")){returnParseSupportsConditionTermsAfterOperator(aConditionMet,eAnd);}if(mToken.mIdent.LowerCaseEqualsLiteral("or")){returnParseSupportsConditionTermsAfterOperator(aConditionMet,eOr);}UngetToken();returntrue;}// supports_condition_terms_after_operator(operator)// : S+ supports_condition_in_parens ( <operator> supports_condition_in_parens )*// ;boolCSSParserImpl::ParseSupportsConditionTermsAfterOperator(bool&aConditionMet,CSSParserImpl::SupportsConditionTermOperatoraOperator){if(!RequireWhitespace()){REPORT_UNEXPECTED(PESupportsWhitespaceRequired);returnfalse;}constchar*token=aOperator==eAnd?"and":"or";for(;;){booltermConditionMet=false;if(!ParseSupportsConditionInParens(termConditionMet)){returnfalse;}aConditionMet=aOperator==eAnd?aConditionMet&&termConditionMet:aConditionMet||termConditionMet;if(!GetToken(true)){returntrue;}if(mToken.mType!=eCSSToken_Ident||!mToken.mIdent.LowerCaseEqualsASCII(token)){UngetToken();returntrue;}}}boolCSSParserImpl::SkipUntil(PRUnicharaStopSymbol){nsCSSToken*tk=&mToken;nsAutoTArray<PRUnichar,16>stack;stack.AppendElement(aStopSymbol);for(;;){if(!GetToken(true)){returnfalse;}if(eCSSToken_Symbol==tk->mType){PRUnicharsymbol=tk->mSymbol;uint32_tstackTopIndex=stack.Length()-1;if(symbol==stack.ElementAt(stackTopIndex)){stack.RemoveElementAt(stackTopIndex);if(stackTopIndex==0){returntrue;}// Just handle out-of-memory by parsing incorrectly. It's// highly unlikely we're dealing with a legitimate style sheet// anyway.}elseif('{'==symbol){stack.AppendElement('}');}elseif('['==symbol){stack.AppendElement(']');}elseif('('==symbol){stack.AppendElement(')');}}elseif(eCSSToken_Function==tk->mType||eCSSToken_Bad_URL==tk->mType){stack.AppendElement(')');}}}voidCSSParserImpl::SkipUntilOneOf(constPRUnichar*aStopSymbolChars){nsCSSToken*tk=&mToken;nsDependentStringstopSymbolChars(aStopSymbolChars);for(;;){if(!GetToken(true)){break;}if(eCSSToken_Symbol==tk->mType){PRUnicharsymbol=tk->mSymbol;if(stopSymbolChars.FindChar(symbol)!=-1){break;}elseif('{'==symbol){SkipUntil('}');}elseif('['==symbol){SkipUntil(']');}elseif('('==symbol){SkipUntil(')');}}elseif(eCSSToken_Function==tk->mType||eCSSToken_Bad_URL==tk->mType){SkipUntil(')');}}}boolCSSParserImpl::SkipDeclaration(boolaCheckForBraces){nsCSSToken*tk=&mToken;for(;;){if(!GetToken(true)){if(aCheckForBraces){REPORT_UNEXPECTED_EOF(PESkipDeclBraceEOF);}returnfalse;}if(eCSSToken_Symbol==tk->mType){PRUnicharsymbol=tk->mSymbol;if(';'==symbol){break;}if(aCheckForBraces){if('}'==symbol){UngetToken();break;}}if('{'==symbol){SkipUntil('}');}elseif('('==symbol){SkipUntil(')');}elseif('['==symbol){SkipUntil(']');}}elseif(eCSSToken_Function==tk->mType||eCSSToken_Bad_URL==tk->mType){SkipUntil(')');}}returntrue;}voidCSSParserImpl::SkipRuleSet(boolaInsideBraces){nsCSSToken*tk=&mToken;for(;;){if(!GetToken(true)){REPORT_UNEXPECTED_EOF(PESkipRSBraceEOF);break;}if(eCSSToken_Symbol==tk->mType){PRUnicharsymbol=tk->mSymbol;if('}'==symbol&&aInsideBraces){// leave block closer for higher-level grammar to consumeUngetToken();break;}elseif('{'==symbol){SkipUntil('}');break;}elseif('('==symbol){SkipUntil(')');}elseif('['==symbol){SkipUntil(']');}}elseif(eCSSToken_Function==tk->mType||eCSSToken_Bad_URL==tk->mType){SkipUntil(')');}}}voidCSSParserImpl::PushGroup(css::GroupRule*aRule){mGroupStack.AppendElement(aRule);}voidCSSParserImpl::PopGroup(){uint32_tcount=mGroupStack.Length();if(0<count){mGroupStack.RemoveElementAt(count-1);}}voidCSSParserImpl::AppendRule(css::Rule*aRule){uint32_tcount=mGroupStack.Length();if(0<count){mGroupStack[count-1]->AppendStyleRule(aRule);}else{mSheet->AppendStyleRule(aRule);}}boolCSSParserImpl::ParseRuleSet(RuleAppendFuncaAppendFunc,void*aData,boolaInsideBraces){// First get the list of selectors for the rulensCSSSelectorList*slist=nullptr;uint32_tlinenum=mScanner->GetLineNumber();if(!ParseSelectorList(slist,PRUnichar('{'))){REPORT_UNEXPECTED(PEBadSelectorRSIgnored);OUTPUT_ERROR();SkipRuleSet(aInsideBraces);returnfalse;}NS_ASSERTION(nullptr!=slist,"null selector list");CLEAR_ERROR();// Next parse the declaration blockuint32_tparseFlags=eParseDeclaration_InBraces|eParseDeclaration_AllowImportant;css::Declaration*declaration=ParseDeclarationBlock(parseFlags);if(nullptr==declaration){deleteslist;returnfalse;}#if 0 slist->Dump(); fputs("{\n", stdout); declaration->List(); fputs("}\n", stdout);#endif// Translate the selector list and declaration block into style datansRefPtr<css::StyleRule>rule=newcss::StyleRule(slist,declaration);rule->SetLineNumber(linenum);(*aAppendFunc)(rule,aData);returntrue;}boolCSSParserImpl::ParseSelectorList(nsCSSSelectorList*&aListHead,PRUnicharaStopChar){nsCSSSelectorList*list=nullptr;if(!ParseSelectorGroup(list)){// must have at least one selector groupaListHead=nullptr;returnfalse;}NS_ASSERTION(nullptr!=list,"no selector list");aListHead=list;// After that there must either be a "," or a "{" (the latter if// StopChar is nonzero)nsCSSToken*tk=&mToken;for(;;){if(!GetToken(true)){if(aStopChar==PRUnichar(0)){returntrue;}REPORT_UNEXPECTED_EOF(PESelectorListExtraEOF);break;}if(eCSSToken_Symbol==tk->mType){if(','==tk->mSymbol){nsCSSSelectorList*newList=nullptr;// Another selector group must followif(!ParseSelectorGroup(newList)){break;}// add new list to the end of the selector listlist->mNext=newList;list=newList;continue;}elseif(aStopChar==tk->mSymbol&&aStopChar!=PRUnichar(0)){UngetToken();returntrue;}}REPORT_UNEXPECTED_TOKEN(PESelectorListExtra);UngetToken();break;}deleteaListHead;aListHead=nullptr;returnfalse;}staticboolIsUniversalSelector(constnsCSSSelector&aSelector){returnbool((aSelector.mNameSpace==kNameSpaceID_Unknown)&&(aSelector.mLowercaseTag==nullptr)&&(aSelector.mIDList==nullptr)&&(aSelector.mClassList==nullptr)&&(aSelector.mAttrList==nullptr)&&(aSelector.mNegations==nullptr)&&(aSelector.mPseudoClassList==nullptr));}boolCSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*&aList){PRUnicharcombinator=0;nsAutoPtr<nsCSSSelectorList>list(newnsCSSSelectorList());for(;;){if(!ParseSelector(list,combinator)){returnfalse;}// Look for a combinator.if(!GetToken(false)){break;// EOF ok here}combinator=PRUnichar(0);if(mToken.mType==eCSSToken_Whitespace){if(!GetToken(true)){break;// EOF ok here}combinator=PRUnichar(' ');}if(mToken.mType!=eCSSToken_Symbol){UngetToken();// not a combinator}else{PRUnicharsymbol=mToken.mSymbol;if(symbol=='+'||symbol=='>'||symbol=='~'){combinator=mToken.mSymbol;}else{UngetToken();// not a combinatorif(symbol==','||symbol=='{'||symbol==')'){break;// end of selector group}}}if(!combinator){REPORT_UNEXPECTED_TOKEN(PESelectorListExtra);returnfalse;}}aList=list.forget();returntrue;}#define SEL_MASK_NSPACE 0x01#define SEL_MASK_ELEM 0x02#define SEL_MASK_ID 0x04#define SEL_MASK_CLASS 0x08#define SEL_MASK_ATTRIB 0x10#define SEL_MASK_PCLASS 0x20#define SEL_MASK_PELEM 0x40//// Parses an ID selector #name//CSSParserImpl::nsSelectorParsingStatusCSSParserImpl::ParseIDSelector(int32_t&aDataMask,nsCSSSelector&aSelector){NS_ASSERTION(!mToken.mIdent.IsEmpty(),"Empty mIdent in eCSSToken_ID token?");aDataMask|=SEL_MASK_ID;aSelector.AddID(mToken.mIdent);returneSelectorParsingStatus_Continue;}//// Parses a class selector .name//CSSParserImpl::nsSelectorParsingStatusCSSParserImpl::ParseClassSelector(int32_t&aDataMask,nsCSSSelector&aSelector){if(!GetToken(false)){// get identREPORT_UNEXPECTED_EOF(PEClassSelEOF);returneSelectorParsingStatus_Error;}if(eCSSToken_Ident!=mToken.mType){// malformed selectorREPORT_UNEXPECTED_TOKEN(PEClassSelNotIdent);UngetToken();returneSelectorParsingStatus_Error;}aDataMask|=SEL_MASK_CLASS;aSelector.AddClass(mToken.mIdent);returneSelectorParsingStatus_Continue;}//// Parse a type element selector or a universal selector// namespace|type or namespace|* or *|* or *//CSSParserImpl::nsSelectorParsingStatusCSSParserImpl::ParseTypeOrUniversalSelector(int32_t&aDataMask,nsCSSSelector&aSelector,boolaIsNegated){nsAutoStringbuffer;if(mToken.IsSymbol('*')){// universal element selector, or universal namespaceif(ExpectSymbol('|',false)){// was namespaceaDataMask|=SEL_MASK_NSPACE;aSelector.SetNameSpace(kNameSpaceID_Unknown);// namespace wildcardif(!GetToken(false)){REPORT_UNEXPECTED_EOF(PETypeSelEOF);returneSelectorParsingStatus_Error;}if(eCSSToken_Ident==mToken.mType){// element nameaDataMask|=SEL_MASK_ELEM;aSelector.SetTag(mToken.mIdent);}elseif(mToken.IsSymbol('*')){// universal selectoraDataMask|=SEL_MASK_ELEM;// don't set tag}else{REPORT_UNEXPECTED_TOKEN(PETypeSelNotType);UngetToken();returneSelectorParsingStatus_Error;}}else{// was universal element selectorSetDefaultNamespaceOnSelector(aSelector);aDataMask|=SEL_MASK_ELEM;// don't set any tag in the selector}if(!GetToken(false)){// premature eof is ok (here!)returneSelectorParsingStatus_Done;}}elseif(eCSSToken_Ident==mToken.mType){// element name or namespace namebuffer=mToken.mIdent;// hang on to identif(ExpectSymbol('|',false)){// was namespaceaDataMask|=SEL_MASK_NSPACE;int32_tnameSpaceID=GetNamespaceIdForPrefix(buffer);if(nameSpaceID==kNameSpaceID_Unknown){returneSelectorParsingStatus_Error;}aSelector.SetNameSpace(nameSpaceID);if(!GetToken(false)){REPORT_UNEXPECTED_EOF(PETypeSelEOF);returneSelectorParsingStatus_Error;}if(eCSSToken_Ident==mToken.mType){// element nameaDataMask|=SEL_MASK_ELEM;aSelector.SetTag(mToken.mIdent);}elseif(mToken.IsSymbol('*')){// universal selectoraDataMask|=SEL_MASK_ELEM;// don't set tag}else{REPORT_UNEXPECTED_TOKEN(PETypeSelNotType);UngetToken();returneSelectorParsingStatus_Error;}}else{// was element nameSetDefaultNamespaceOnSelector(aSelector);aSelector.SetTag(buffer);aDataMask|=SEL_MASK_ELEM;}if(!GetToken(false)){// premature eof is ok (here!)returneSelectorParsingStatus_Done;}}elseif(mToken.IsSymbol('|')){// No namespaceaDataMask|=SEL_MASK_NSPACE;aSelector.SetNameSpace(kNameSpaceID_None);// explicit NO namespace// get mandatory tagif(!GetToken(false)){REPORT_UNEXPECTED_EOF(PETypeSelEOF);returneSelectorParsingStatus_Error;}if(eCSSToken_Ident==mToken.mType){// element nameaDataMask|=SEL_MASK_ELEM;aSelector.SetTag(mToken.mIdent);}elseif(mToken.IsSymbol('*')){// universal selectoraDataMask|=SEL_MASK_ELEM;// don't set tag}else{REPORT_UNEXPECTED_TOKEN(PETypeSelNotType);UngetToken();returneSelectorParsingStatus_Error;}if(!GetToken(false)){// premature eof is ok (here!)returneSelectorParsingStatus_Done;}}else{SetDefaultNamespaceOnSelector(aSelector);}if(aIsNegated){// restore last token read in case of a negated type selectorUngetToken();}returneSelectorParsingStatus_Continue;}//// Parse attribute selectors [attr], [attr=value], [attr|=value],// [attr~=value], [attr^=value], [attr$=value] and [attr*=value]//CSSParserImpl::nsSelectorParsingStatusCSSParserImpl::ParseAttributeSelector(int32_t&aDataMask,nsCSSSelector&aSelector){if(!GetToken(true)){// premature EOFREPORT_UNEXPECTED_EOF(PEAttributeNameEOF);returneSelectorParsingStatus_Error;}int32_tnameSpaceID=kNameSpaceID_None;nsAutoStringattr;if(mToken.IsSymbol('*')){// wildcard namespacenameSpaceID=kNameSpaceID_Unknown;if(ExpectSymbol('|',false)){if(!GetToken(false)){// premature EOFREPORT_UNEXPECTED_EOF(PEAttributeNameEOF);returneSelectorParsingStatus_Error;}if(eCSSToken_Ident==mToken.mType){// attr nameattr=mToken.mIdent;}else{REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected);UngetToken();returneSelectorParsingStatus_Error;}}else{REPORT_UNEXPECTED_TOKEN(PEAttSelNoBar);returneSelectorParsingStatus_Error;}}elseif(mToken.IsSymbol('|')){// NO namespaceif(!GetToken(false)){// premature EOFREPORT_UNEXPECTED_EOF(PEAttributeNameEOF);returneSelectorParsingStatus_Error;}if(eCSSToken_Ident==mToken.mType){// attr nameattr=mToken.mIdent;}else{REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected);UngetToken();returneSelectorParsingStatus_Error;}}elseif(eCSSToken_Ident==mToken.mType){// attr name or namespaceattr=mToken.mIdent;// hang on to itif(ExpectSymbol('|',false)){// was a namespacenameSpaceID=GetNamespaceIdForPrefix(attr);if(nameSpaceID==kNameSpaceID_Unknown){returneSelectorParsingStatus_Error;}if(!GetToken(false)){// premature EOFREPORT_UNEXPECTED_EOF(PEAttributeNameEOF);returneSelectorParsingStatus_Error;}if(eCSSToken_Ident==mToken.mType){// attr nameattr=mToken.mIdent;}else{REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected);UngetToken();returneSelectorParsingStatus_Error;}}}else{// malformedREPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected);UngetToken();returneSelectorParsingStatus_Error;}if(!GetToken(true)){// premature EOFREPORT_UNEXPECTED_EOF(PEAttSelInnerEOF);returneSelectorParsingStatus_Error;}if((eCSSToken_Symbol==mToken.mType)||(eCSSToken_Includes==mToken.mType)||(eCSSToken_Dashmatch==mToken.mType)||(eCSSToken_Beginsmatch==mToken.mType)||(eCSSToken_Endsmatch==mToken.mType)||(eCSSToken_Containsmatch==mToken.mType)){uint8_tfunc;if(eCSSToken_Includes==mToken.mType){func=NS_ATTR_FUNC_INCLUDES;}elseif(eCSSToken_Dashmatch==mToken.mType){func=NS_ATTR_FUNC_DASHMATCH;}elseif(eCSSToken_Beginsmatch==mToken.mType){func=NS_ATTR_FUNC_BEGINSMATCH;}elseif(eCSSToken_Endsmatch==mToken.mType){func=NS_ATTR_FUNC_ENDSMATCH;}elseif(eCSSToken_Containsmatch==mToken.mType){func=NS_ATTR_FUNC_CONTAINSMATCH;}elseif(']'==mToken.mSymbol){aDataMask|=SEL_MASK_ATTRIB;aSelector.AddAttribute(nameSpaceID,attr);func=NS_ATTR_FUNC_SET;}elseif('='==mToken.mSymbol){func=NS_ATTR_FUNC_EQUALS;}else{REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected);UngetToken();// bad functionreturneSelectorParsingStatus_Error;}if(NS_ATTR_FUNC_SET!=func){// get valueif(!GetToken(true)){// premature EOFREPORT_UNEXPECTED_EOF(PEAttSelValueEOF);returneSelectorParsingStatus_Error;}if((eCSSToken_Ident==mToken.mType)||(eCSSToken_String==mToken.mType)){nsAutoStringvalue(mToken.mIdent);if(!GetToken(true)){// premature EOFREPORT_UNEXPECTED_EOF(PEAttSelCloseEOF);returneSelectorParsingStatus_Error;}if(mToken.IsSymbol(']')){boolisCaseSensitive=true;// For cases when this style sheet is applied to an HTML// element in an HTML document, and the attribute selector is// for a non-namespaced attribute, then check to see if it's// one of the known attributes whose VALUE is// case-insensitive.if(nameSpaceID==kNameSpaceID_None){staticconstchar*caseInsensitiveHTMLAttribute[]={// list based on http://www.w3.org/TR/html4/"lang","dir","http-equiv","text","link","vlink","alink","compact","align","frame","rules","valign","scope","axis","nowrap","hreflang","rel","rev","charset","codetype","declare","valuetype","shape","nohref","media","bgcolor","clear","color","face","noshade","noresize","scrolling","target","method","enctype","accept-charset","accept","checked","multiple","selected","disabled","readonly","language","defer","type",// additional attributes not in HTML4"direction",// marqueenullptr};shorti=0;constchar*htmlAttr;while((htmlAttr=caseInsensitiveHTMLAttribute[i++])){if(attr.LowerCaseEqualsASCII(htmlAttr)){isCaseSensitive=false;break;}}}aDataMask|=SEL_MASK_ATTRIB;aSelector.AddAttribute(nameSpaceID,attr,func,value,isCaseSensitive);}else{REPORT_UNEXPECTED_TOKEN(PEAttSelNoClose);UngetToken();returneSelectorParsingStatus_Error;}}else{REPORT_UNEXPECTED_TOKEN(PEAttSelBadValue);UngetToken();returneSelectorParsingStatus_Error;}}}else{REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected);UngetToken();// bad dog, no biscut!returneSelectorParsingStatus_Error;}returneSelectorParsingStatus_Continue;}//// Parse pseudo-classes and pseudo-elements//CSSParserImpl::nsSelectorParsingStatusCSSParserImpl::ParsePseudoSelector(int32_t&aDataMask,nsCSSSelector&aSelector,boolaIsNegated,nsIAtom**aPseudoElement,nsAtomList**aPseudoElementArgs,nsCSSPseudoElements::Type*aPseudoElementType){NS_ASSERTION(aIsNegated||(aPseudoElement&&aPseudoElementArgs),"expected location to store pseudo element");NS_ASSERTION(!aIsNegated||(!aPseudoElement&&!aPseudoElementArgs),"negated selectors shouldn't have a place to store ""pseudo elements");if(!GetToken(false)){// premature eofREPORT_UNEXPECTED_EOF(PEPseudoSelEOF);returneSelectorParsingStatus_Error;}// First, find out whether we are parsing a CSS3 pseudo-elementboolparsingPseudoElement=false;if(mToken.IsSymbol(':')){parsingPseudoElement=true;if(!GetToken(false)){// premature eofREPORT_UNEXPECTED_EOF(PEPseudoSelEOF);returneSelectorParsingStatus_Error;}}// Do some sanity-checking on the tokenif(eCSSToken_Ident!=mToken.mType&&eCSSToken_Function!=mToken.mType){// malformed selectorREPORT_UNEXPECTED_TOKEN(PEPseudoSelBadName);UngetToken();returneSelectorParsingStatus_Error;}// OK, now we know we have an mIdent. Atomize it. All the atoms, for// pseudo-classes as well as pseudo-elements, start with a single ':'.nsAutoStringbuffer;buffer.Append(PRUnichar(':'));buffer.Append(mToken.mIdent);nsContentUtils::ASCIIToLower(buffer);nsCOMPtr<nsIAtom>pseudo=do_GetAtom(buffer);if(!pseudo){NS_RUNTIMEABORT("do_GetAtom failed - out of memory?");}// stash away some info about this pseudo so we only have to get it once.boolisTreePseudo=false;nsCSSPseudoElements::TypepseudoElementType=nsCSSPseudoElements::GetPseudoType(pseudo);nsCSSPseudoClasses::TypepseudoClassType=nsCSSPseudoClasses::GetPseudoType(pseudo);// We currently allow :-moz-placeholder and ::-moz-placeholder. We have to// be a bit stricter regarding the pseudo-element parsing rules.if(pseudoElementType==nsCSSPseudoElements::ePseudo_mozPlaceholder&&pseudoClassType==nsCSSPseudoClasses::ePseudoClass_mozPlaceholder){if(parsingPseudoElement){pseudoClassType=nsCSSPseudoClasses::ePseudoClass_NotPseudoClass;}else{pseudoElementType=nsCSSPseudoElements::ePseudo_NotPseudoElement;}}#ifdef MOZ_XULisTreePseudo=(pseudoElementType==nsCSSPseudoElements::ePseudo_XULTree);// If a tree pseudo-element is using the function syntax, it will// get isTree set here and will pass the check below that only// allows functions if they are in our list of things allowed to be// functions. If it is _not_ using the function syntax, isTree will// be false, and it will still pass that check. So the tree// pseudo-elements are allowed to be either functions or not, as// desired.boolisTree=(eCSSToken_Function==mToken.mType)&&isTreePseudo;#endifboolisPseudoElement=(pseudoElementType<nsCSSPseudoElements::ePseudo_PseudoElementCount);// anonymous boxes are only allowed if they're the tree boxes or we have// enabled unsafe rulesboolisAnonBox=isTreePseudo||(pseudoElementType==nsCSSPseudoElements::ePseudo_AnonBox&&mUnsafeRulesEnabled);boolisPseudoClass=(pseudoClassType!=nsCSSPseudoClasses::ePseudoClass_NotPseudoClass);NS_ASSERTION(!isPseudoClass||pseudoElementType==nsCSSPseudoElements::ePseudo_NotPseudoElement,"Why is this atom both a pseudo-class and a pseudo-element?");NS_ASSERTION(isPseudoClass+isPseudoElement+isAnonBox<=1,"Shouldn't be more than one of these");if(!isPseudoClass&&!isPseudoElement&&!isAnonBox){// Not a pseudo-class, not a pseudo-element.... forget itREPORT_UNEXPECTED_TOKEN(PEPseudoSelUnknown);UngetToken();returneSelectorParsingStatus_Error;}// If it's a function token, it better be on our "ok" list, and if the name// is that of a function pseudo it better be a function tokenif((eCSSToken_Function==mToken.mType)!=(#ifdef MOZ_XULisTree||#endifnsCSSPseudoClasses::ePseudoClass_notPseudo==pseudoClassType||nsCSSPseudoClasses::HasStringArg(pseudoClassType)||nsCSSPseudoClasses::HasNthPairArg(pseudoClassType)||nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType))){// There are no other function pseudosREPORT_UNEXPECTED_TOKEN(PEPseudoSelNonFunc);UngetToken();returneSelectorParsingStatus_Error;}// If it starts with "::", it better be a pseudo-elementif(parsingPseudoElement&&!isPseudoElement&&!isAnonBox){REPORT_UNEXPECTED_TOKEN(PEPseudoSelNotPE);UngetToken();returneSelectorParsingStatus_Error;}if(!parsingPseudoElement&&nsCSSPseudoClasses::ePseudoClass_notPseudo==pseudoClassType){if(aIsNegated){// :not() can't be itself negatedREPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot);UngetToken();returneSelectorParsingStatus_Error;}// CSS 3 Negation pseudo-class takes one simple selector as argumentnsSelectorParsingStatusparsingStatus=ParseNegatedSimpleSelector(aDataMask,aSelector);if(eSelectorParsingStatus_Continue!=parsingStatus){returnparsingStatus;}}elseif(!parsingPseudoElement&&isPseudoClass){aDataMask|=SEL_MASK_PCLASS;if(eCSSToken_Function==mToken.mType){nsSelectorParsingStatusparsingStatus;if(nsCSSPseudoClasses::HasStringArg(pseudoClassType)){parsingStatus=ParsePseudoClassWithIdentArg(aSelector,pseudoClassType);}elseif(nsCSSPseudoClasses::HasNthPairArg(pseudoClassType)){parsingStatus=ParsePseudoClassWithNthPairArg(aSelector,pseudoClassType);}else{NS_ABORT_IF_FALSE(nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType),"unexpected pseudo with function token");parsingStatus=ParsePseudoClassWithSelectorListArg(aSelector,pseudoClassType);}if(eSelectorParsingStatus_Continue!=parsingStatus){if(eSelectorParsingStatus_Error==parsingStatus){SkipUntil(')');}returnparsingStatus;}}else{aSelector.AddPseudoClass(pseudoClassType);}}elseif(isPseudoElement||isAnonBox){// Pseudo-element. Make some more sanity checks.if(aIsNegated){// pseudo-elements can't be negatedREPORT_UNEXPECTED_TOKEN(PEPseudoSelPEInNot);UngetToken();returneSelectorParsingStatus_Error;}// CSS2 pseudo-elements and -moz-tree-* pseudo-elements are allowed// to have a single ':' on them. Others (CSS3+ pseudo-elements and// various -moz-* pseudo-elements) must have |parsingPseudoElement|// set.if(!parsingPseudoElement&&!nsCSSPseudoElements::IsCSS2PseudoElement(pseudo)#ifdef MOZ_XUL&&!isTreePseudo#endif){REPORT_UNEXPECTED_TOKEN(PEPseudoSelNewStyleOnly);UngetToken();returneSelectorParsingStatus_Error;}if(0==(aDataMask&SEL_MASK_PELEM)){aDataMask|=SEL_MASK_PELEM;NS_ADDREF(*aPseudoElement=pseudo);*aPseudoElementType=pseudoElementType;#ifdef MOZ_XULif(isTree){// We have encountered a pseudoelement of the form// -moz-tree-xxxx(a,b,c). We parse (a,b,c) and add each// item in the list to the pseudoclass list. They will be pulled// from the list later along with the pseudo-element.if(!ParseTreePseudoElement(aPseudoElementArgs)){returneSelectorParsingStatus_Error;}}#endif// the next *non*whitespace token must be '{' or ',' or EOFif(!GetToken(true)){// premature eof is ok (here!)returneSelectorParsingStatus_Done;}if((mToken.IsSymbol('{')||mToken.IsSymbol(','))){UngetToken();returneSelectorParsingStatus_Done;}REPORT_UNEXPECTED_TOKEN(PEPseudoSelTrailing);UngetToken();returneSelectorParsingStatus_Error;}else{// multiple pseudo elements, not legalREPORT_UNEXPECTED_TOKEN(PEPseudoSelMultiplePE);UngetToken();returneSelectorParsingStatus_Error;}}#ifdef DEBUGelse{// We should never end up here. Indeed, if we ended up here, we know (from// the current if/else cascade) that !isPseudoElement and !isAnonBox. But// then due to our earlier check we know that isPseudoClass. Since we// didn't fall into the isPseudoClass case in this cascade, we must have// parsingPseudoElement. But we've already checked the// parsingPseudoElement && !isPseudoClass && !isAnonBox case and bailed if// it's happened.NS_NOTREACHED("How did this happen?");}#endifreturneSelectorParsingStatus_Continue;}//// Parse the argument of a negation pseudo-class :not()//CSSParserImpl::nsSelectorParsingStatusCSSParserImpl::ParseNegatedSimpleSelector(int32_t&aDataMask,nsCSSSelector&aSelector){if(!GetToken(true)){// premature eofREPORT_UNEXPECTED_EOF(PENegationEOF);returneSelectorParsingStatus_Error;}if(mToken.IsSymbol(')')){REPORT_UNEXPECTED_TOKEN(PENegationBadArg);returneSelectorParsingStatus_Error;}// Create a new nsCSSSelector and add it to the end of// aSelector.mNegations.// Given the current parsing rules, every selector in mNegations// contains only one simple selector (css3 definition) within it.// This could easily change in future versions of CSS, and the only// thing we need to change to support that is this parsing code and the// serialization code for nsCSSSelector.nsCSSSelector*newSel=newnsCSSSelector();nsCSSSelector*negations=&aSelector;while(negations->mNegations){negations=negations->mNegations;}negations->mNegations=newSel;nsSelectorParsingStatusparsingStatus;if(eCSSToken_ID==mToken.mType){// #idparsingStatus=ParseIDSelector(aDataMask,*newSel);}elseif(mToken.IsSymbol('.')){// .classparsingStatus=ParseClassSelector(aDataMask,*newSel);}elseif(mToken.IsSymbol(':')){// :pseudoparsingStatus=ParsePseudoSelector(aDataMask,*newSel,true,nullptr,nullptr,nullptr);}elseif(mToken.IsSymbol('[')){// [attributeparsingStatus=ParseAttributeSelector(aDataMask,*newSel);if(eSelectorParsingStatus_Error==parsingStatus){// Skip forward to the matching ']'SkipUntil(']');}}else{// then it should be a type element or universal selectorparsingStatus=ParseTypeOrUniversalSelector(aDataMask,*newSel,true);}if(eSelectorParsingStatus_Error==parsingStatus){REPORT_UNEXPECTED_TOKEN(PENegationBadInner);SkipUntil(')');returnparsingStatus;}// close the parenthesisif(!ExpectSymbol(')',true)){REPORT_UNEXPECTED_TOKEN(PENegationNoClose);SkipUntil(')');returneSelectorParsingStatus_Error;}NS_ASSERTION(newSel->mNameSpace==kNameSpaceID_Unknown||(!newSel->mIDList&&!newSel->mClassList&&!newSel->mPseudoClassList&&!newSel->mAttrList),"Need to fix the serialization code to deal with this");returneSelectorParsingStatus_Continue;}//// Parse the argument of a pseudo-class that has an ident arg//CSSParserImpl::nsSelectorParsingStatusCSSParserImpl::ParsePseudoClassWithIdentArg(nsCSSSelector&aSelector,nsCSSPseudoClasses::TypeaType){if(!GetToken(true)){// premature eofREPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF);returneSelectorParsingStatus_Error;}// We expect an identifier with a language abbreviationif(eCSSToken_Ident!=mToken.mType){REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotIdent);UngetToken();returneSelectorParsingStatus_Error;// our caller calls SkipUntil(')')}// -moz-locale-dir and -moz-dir can only have values of 'ltr' or 'rtl'.if(aType==nsCSSPseudoClasses::ePseudoClass_mozLocaleDir||aType==nsCSSPseudoClasses::ePseudoClass_dir){nsContentUtils::ASCIIToLower(mToken.mIdent);// case insensitiveif(!mToken.mIdent.EqualsLiteral("ltr")&&!mToken.mIdent.EqualsLiteral("rtl")){REPORT_UNEXPECTED_TOKEN(PEBadDirValue);returneSelectorParsingStatus_Error;// our caller calls SkipUntil(')')}}// Add the pseudo with the language parameteraSelector.AddPseudoClass(aType,mToken.mIdent.get());// close the parenthesisif(!ExpectSymbol(')',true)){REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose);returneSelectorParsingStatus_Error;// our caller calls SkipUntil(')')}returneSelectorParsingStatus_Continue;}CSSParserImpl::nsSelectorParsingStatusCSSParserImpl::ParsePseudoClassWithNthPairArg(nsCSSSelector&aSelector,nsCSSPseudoClasses::TypeaType){int32_tnumbers[2]={0,0};boollookForB=true;// Follow the whitespace rules as proposed in// http://lists.w3.org/Archives/Public/www-style/2008Mar/0121.htmlif(!GetToken(true)){REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF);returneSelectorParsingStatus_Error;}if(eCSSToken_Ident==mToken.mType||eCSSToken_Dimension==mToken.mType){// The CSS tokenization doesn't handle :nth-child() containing - well:// 2n-1 is a dimension// n-1 is an identifier// The easiest way to deal with that is to push everything from the// minus on back onto the scanner's pushback buffer.uint32_ttruncAt=0;if(StringBeginsWith(mToken.mIdent,NS_LITERAL_STRING("n-"))){truncAt=1;}elseif(StringBeginsWith(mToken.mIdent,NS_LITERAL_STRING("-n-"))){truncAt=2;}if(truncAt!=0){mScanner->Backup(mToken.mIdent.Length()-truncAt);mToken.mIdent.Truncate(truncAt);}}if(eCSSToken_Ident==mToken.mType){if(mToken.mIdent.LowerCaseEqualsLiteral("odd")){numbers[0]=2;numbers[1]=1;lookForB=false;}elseif(mToken.mIdent.LowerCaseEqualsLiteral("even")){numbers[0]=2;numbers[1]=0;lookForB=false;}elseif(mToken.mIdent.LowerCaseEqualsLiteral("n")){numbers[0]=1;}elseif(mToken.mIdent.LowerCaseEqualsLiteral("-n")){numbers[0]=-1;}else{REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth);returneSelectorParsingStatus_Error;// our caller calls SkipUntil(')')}}elseif(eCSSToken_Number==mToken.mType){if(!mToken.mIntegerValid){REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth);returneSelectorParsingStatus_Error;// our caller calls SkipUntil(')')}numbers[1]=mToken.mInteger;lookForB=false;}elseif(eCSSToken_Dimension==mToken.mType){if(!mToken.mIntegerValid||!mToken.mIdent.LowerCaseEqualsLiteral("n")){REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth);returneSelectorParsingStatus_Error;// our caller calls SkipUntil(')')}numbers[0]=mToken.mInteger;}// XXX If it's a ')', is that valid? (as 0n+0)else{REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth);UngetToken();returneSelectorParsingStatus_Error;// our caller calls SkipUntil(')')}if(!GetToken(true)){REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF);returneSelectorParsingStatus_Error;}if(lookForB&&!mToken.IsSymbol(')')){// The '+' or '-' sign can optionally be separated by whitespace.// If it is separated by whitespace from what follows it, it appears// as a separate token rather than part of the number token.boolhaveSign=false;int32_tsign=1;if(mToken.IsSymbol('+')||mToken.IsSymbol('-')){haveSign=true;if(mToken.IsSymbol('-')){sign=-1;}if(!GetToken(true)){REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF);returneSelectorParsingStatus_Error;}}if(eCSSToken_Number!=mToken.mType||!mToken.mIntegerValid||mToken.mHasSign==haveSign){REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth);returneSelectorParsingStatus_Error;// our caller calls SkipUntil(')')}numbers[1]=mToken.mInteger*sign;if(!GetToken(true)){REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF);returneSelectorParsingStatus_Error;}}if(!mToken.IsSymbol(')')){REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose);returneSelectorParsingStatus_Error;// our caller calls SkipUntil(')')}aSelector.AddPseudoClass(aType,numbers);returneSelectorParsingStatus_Continue;}//// Parse the argument of a pseudo-class that has a selector list argument.// Such selector lists cannot contain combinators, but can contain// anything that goes between a pair of combinators.//CSSParserImpl::nsSelectorParsingStatusCSSParserImpl::ParsePseudoClassWithSelectorListArg(nsCSSSelector&aSelector,nsCSSPseudoClasses::TypeaType){nsAutoPtr<nsCSSSelectorList>slist;if(!ParseSelectorList(*getter_Transfers(slist),PRUnichar(')'))){returneSelectorParsingStatus_Error;// our caller calls SkipUntil(')')}// Check that none of the selectors in the list have combinators or// pseudo-elements.for(nsCSSSelectorList*l=slist;l;l=l->mNext){nsCSSSelector*s=l->mSelectors;if(s->mNext||s->IsPseudoElement()){returneSelectorParsingStatus_Error;// our caller calls SkipUntil(')')}}// Add the pseudo with the selector list parameteraSelector.AddPseudoClass(aType,slist.forget());// close the parenthesisif(!ExpectSymbol(')',true)){REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose);returneSelectorParsingStatus_Error;// our caller calls SkipUntil(')')}returneSelectorParsingStatus_Continue;}/** * This is the format for selectors: * operator? [[namespace |]? element_name]? [ ID | class | attrib | pseudo ]* */boolCSSParserImpl::ParseSelector(nsCSSSelectorList*aList,PRUnicharaPrevCombinator){if(!GetToken(true)){REPORT_UNEXPECTED_EOF(PESelectorEOF);returnfalse;}nsCSSSelector*selector=aList->AddSelector(aPrevCombinator);nsCOMPtr<nsIAtom>pseudoElement;nsAutoPtr<nsAtomList>pseudoElementArgs;nsCSSPseudoElements::TypepseudoElementType=nsCSSPseudoElements::ePseudo_NotPseudoElement;int32_tdataMask=0;nsSelectorParsingStatusparsingStatus=ParseTypeOrUniversalSelector(dataMask,*selector,false);while(parsingStatus==eSelectorParsingStatus_Continue){if(eCSSToken_ID==mToken.mType){// #idparsingStatus=ParseIDSelector(dataMask,*selector);}elseif(mToken.IsSymbol('.')){// .classparsingStatus=ParseClassSelector(dataMask,*selector);}elseif(mToken.IsSymbol(':')){// :pseudoparsingStatus=ParsePseudoSelector(dataMask,*selector,false,getter_AddRefs(pseudoElement),getter_Transfers(pseudoElementArgs),&pseudoElementType);}elseif(mToken.IsSymbol('[')){// [attributeparsingStatus=ParseAttributeSelector(dataMask,*selector);if(eSelectorParsingStatus_Error==parsingStatus){SkipUntil(']');}}else{// not a selector token, we're doneparsingStatus=eSelectorParsingStatus_Done;UngetToken();break;}if(parsingStatus!=eSelectorParsingStatus_Continue){break;}if(!GetToken(false)){// premature eof is ok (here!)parsingStatus=eSelectorParsingStatus_Done;break;}}if(parsingStatus==eSelectorParsingStatus_Error){returnfalse;}if(!dataMask){if(selector->mNext){REPORT_UNEXPECTED(PESelectorGroupExtraCombinator);}else{REPORT_UNEXPECTED(PESelectorGroupNoSelector);}returnfalse;}if(pseudoElementType==nsCSSPseudoElements::ePseudo_AnonBox){// We got an anonymous box pseudo-element; it must be the only// thing in this selector group.if(selector->mNext||!IsUniversalSelector(*selector)){REPORT_UNEXPECTED(PEAnonBoxNotAlone);returnfalse;}// Rewrite the current selector as this pseudo-element.// It does not contribute to selector weight.selector->mLowercaseTag.swap(pseudoElement);selector->mClassList=pseudoElementArgs.forget();selector->SetPseudoType(pseudoElementType);returntrue;}aList->mWeight+=selector->CalcWeight();// Pseudo-elements other than anonymous boxes are represented as// direct children ('>' combinator) of the rest of the selector.if(pseudoElement){selector=aList->AddSelector('>');selector->mLowercaseTag.swap(pseudoElement);selector->mClassList=pseudoElementArgs.forget();selector->SetPseudoType(pseudoElementType);}returntrue;}css::Declaration*CSSParserImpl::ParseDeclarationBlock(uint32_taFlags,nsCSSContextTypeaContext){boolcheckForBraces=(aFlags&eParseDeclaration_InBraces)!=0;if(checkForBraces){if(!ExpectSymbol('{',true)){REPORT_UNEXPECTED_TOKEN(PEBadDeclBlockStart);OUTPUT_ERROR();returnnullptr;}}css::Declaration*declaration=newcss::Declaration();mData.AssertInitialState();if(declaration){for(;;){boolchanged;if(!ParseDeclaration(declaration,aFlags,true,&changed,aContext)){if(!SkipDeclaration(checkForBraces)){break;}if(checkForBraces){if(ExpectSymbol('}',true)){break;}}// Since the skipped declaration didn't end the block we parse// the next declaration.}}declaration->CompressFrom(&mData);}returndeclaration;}// The types to pass to ParseColorComponent. These correspond to the// various datatypes that can go within rgb().#define COLOR_TYPE_UNKNOWN 0#define COLOR_TYPE_INTEGERS 1#define COLOR_TYPE_PERCENTAGES 2boolCSSParserImpl::ParseColor(nsCSSValue&aValue){if(!GetToken(true)){REPORT_UNEXPECTED_EOF(PEColorEOF);returnfalse;}nsCSSToken*tk=&mToken;nscolorrgba;switch(tk->mType){caseeCSSToken_ID:caseeCSSToken_Hash:// #xxyyzzif(NS_HexToRGB(tk->mIdent,&rgba)){aValue.SetColorValue(rgba);returntrue;}break;caseeCSSToken_Ident:if(NS_ColorNameToRGB(tk->mIdent,&rgba)){aValue.SetStringValue(tk->mIdent,eCSSUnit_Ident);returntrue;}else{nsCSSKeywordkeyword=nsCSSKeywords::LookupKeyword(tk->mIdent);if(eCSSKeyword_UNKNOWN<keyword){// known keywordint32_tvalue;if(nsCSSProps::FindKeyword(keyword,nsCSSProps::kColorKTable,value)){aValue.SetIntValue(value,eCSSUnit_EnumColor);returntrue;}}}break;caseeCSSToken_Function:if(mToken.mIdent.LowerCaseEqualsLiteral("rgb")){// rgb ( component , component , component )uint8_tr,g,b;int32_ttype=COLOR_TYPE_UNKNOWN;if(ParseColorComponent(r,type,',')&&ParseColorComponent(g,type,',')&&ParseColorComponent(b,type,')')){aValue.SetColorValue(NS_RGB(r,g,b));returntrue;}SkipUntil(')');returnfalse;}elseif(mToken.mIdent.LowerCaseEqualsLiteral("-moz-rgba")||mToken.mIdent.LowerCaseEqualsLiteral("rgba")){// rgba ( component , component , component , opacity )uint8_tr,g,b,a;int32_ttype=COLOR_TYPE_UNKNOWN;if(ParseColorComponent(r,type,',')&&ParseColorComponent(g,type,',')&&ParseColorComponent(b,type,',')&&ParseColorOpacity(a)){aValue.SetColorValue(NS_RGBA(r,g,b,a));returntrue;}SkipUntil(')');returnfalse;}elseif(mToken.mIdent.LowerCaseEqualsLiteral("hsl")){// hsl ( hue , saturation , lightness )// "hue" is a number, "saturation" and "lightness" are percentages.if(ParseHSLColor(rgba,')')){aValue.SetColorValue(rgba);returntrue;}SkipUntil(')');returnfalse;}elseif(mToken.mIdent.LowerCaseEqualsLiteral("-moz-hsla")||mToken.mIdent.LowerCaseEqualsLiteral("hsla")){// hsla ( hue , saturation , lightness , opacity )// "hue" is a number, "saturation" and "lightness" are percentages,// "opacity" is a number.uint8_ta;if(ParseHSLColor(rgba,',')&&ParseColorOpacity(a)){aValue.SetColorValue(NS_RGBA(NS_GET_R(rgba),NS_GET_G(rgba),NS_GET_B(rgba),a));returntrue;}SkipUntil(')');returnfalse;}break;default:break;}// try 'xxyyzz' without '#' prefix for compatibility with IE and Nav4x (bug 23236 and 45804)if(mHashlessColorQuirk){// - If the string starts with 'a-f', the nsCSSScanner builds the// token as a eCSSToken_Ident and we can parse the string as a// 'xxyyzz' RGB color.// - If it only contains '0-9' digits, the token is a// eCSSToken_Number and it must be converted back to a 6// characters string to be parsed as a RGB color.// - If it starts with '0-9' and contains any 'a-f', the token is a// eCSSToken_Dimension, the mNumber part must be converted back to// a string and the mIdent part must be appended to that string so// that the resulting string has 6 characters.// Note: This is a hack for Nav compatibility. Do not attempt to// simplify it by hacking into the ncCSSScanner. This would be very// bad.nsAutoStringstr;charbuffer[20];switch(tk->mType){caseeCSSToken_Ident:str.Assign(tk->mIdent);break;caseeCSSToken_Number:if(tk->mIntegerValid){PR_snprintf(buffer,sizeof(buffer),"%06d",tk->mInteger);str.AssignWithConversion(buffer);}break;caseeCSSToken_Dimension:if(tk->mIdent.Length()<=6){PR_snprintf(buffer,sizeof(buffer),"%06.0f",tk->mNumber);nsAutoStringtemp;temp.AssignWithConversion(buffer);temp.Right(str,6-tk->mIdent.Length());str.Append(tk->mIdent);}break;default:// There is a whole bunch of cases that are// not handled by this switch. Ignore them.break;}if(NS_HexToRGB(str,&rgba)){aValue.SetColorValue(rgba);returntrue;}}// It's not a colorREPORT_UNEXPECTED_TOKEN(PEColorNotColor);UngetToken();returnfalse;}// aType will be set if we have already parsed other color components// in this color specboolCSSParserImpl::ParseColorComponent(uint8_t&aComponent,int32_t&aType,charaStop){if(!GetToken(true)){REPORT_UNEXPECTED_EOF(PEColorComponentEOF);returnfalse;}floatvalue;nsCSSToken*tk=&mToken;switch(tk->mType){caseeCSSToken_Number:switch(aType){caseCOLOR_TYPE_UNKNOWN:aType=COLOR_TYPE_INTEGERS;break;caseCOLOR_TYPE_INTEGERS:break;caseCOLOR_TYPE_PERCENTAGES:REPORT_UNEXPECTED_TOKEN(PEExpectedPercent);UngetToken();returnfalse;default:NS_NOTREACHED("Someone forgot to add the new color component type in here");}if(!mToken.mIntegerValid){REPORT_UNEXPECTED_TOKEN(PEExpectedInt);UngetToken();returnfalse;}value=tk->mNumber;break;caseeCSSToken_Percentage:switch(aType){caseCOLOR_TYPE_UNKNOWN:aType=COLOR_TYPE_PERCENTAGES;break;caseCOLOR_TYPE_INTEGERS:REPORT_UNEXPECTED_TOKEN(PEExpectedInt);UngetToken();returnfalse;caseCOLOR_TYPE_PERCENTAGES:break;default:NS_NOTREACHED("Someone forgot to add the new color component type in here");}value=tk->mNumber*255.0f;break;default:REPORT_UNEXPECTED_TOKEN(PEColorBadRGBContents);UngetToken();returnfalse;}if(ExpectSymbol(aStop,true)){if(value<0.0f)value=0.0f;if(value>255.0f)value=255.0f;aComponent=NSToIntRound(value);returntrue;}REPORT_UNEXPECTED_TOKEN_CHAR(PEColorComponentBadTerm,aStop);returnfalse;}boolCSSParserImpl::ParseHSLColor(nscolor&aColor,charaStop){floath,s,l;// Get the hueif(!GetToken(true)){REPORT_UNEXPECTED_EOF(PEColorHueEOF);returnfalse;}if(mToken.mType!=eCSSToken_Number){REPORT_UNEXPECTED_TOKEN(PEExpectedNumber);UngetToken();returnfalse;}h=mToken.mNumber;h/=360.0f;// hue values are wraparoundh=h-floor(h);if(!ExpectSymbol(',',true)){REPORT_UNEXPECTED_TOKEN(PEExpectedComma);returnfalse;}// Get the saturationif(!GetToken(true)){REPORT_UNEXPECTED_EOF(PEColorSaturationEOF);returnfalse;}if(mToken.mType!=eCSSToken_Percentage){REPORT_UNEXPECTED_TOKEN(PEExpectedPercent);UngetToken();returnfalse;}s=mToken.mNumber;if(s<0.0f)s=0.0f;if(s>1.0f)s=1.0f;if(!ExpectSymbol(',',true)){REPORT_UNEXPECTED_TOKEN(PEExpectedComma);returnfalse;}// Get the lightnessif(!GetToken(true)){REPORT_UNEXPECTED_EOF(PEColorLightnessEOF);returnfalse;}if(mToken.mType!=eCSSToken_Percentage){REPORT_UNEXPECTED_TOKEN(PEExpectedPercent);UngetToken();returnfalse;}l=mToken.mNumber;if(l<0.0f)l=0.0f;if(l>1.0f)l=1.0f;if(ExpectSymbol(aStop,true)){aColor=NS_HSL2RGB(h,s,l);returntrue;}REPORT_UNEXPECTED_TOKEN_CHAR(PEColorComponentBadTerm,aStop);returnfalse;}boolCSSParserImpl::ParseColorOpacity(uint8_t&aOpacity){if(!GetToken(true)){REPORT_UNEXPECTED_EOF(PEColorOpacityEOF);returnfalse;}if(mToken.mType!=eCSSToken_Number){REPORT_UNEXPECTED_TOKEN(PEExpectedNumber);UngetToken();returnfalse;}if(mToken.mNumber<0.0f){mToken.mNumber=0.0f;}elseif(mToken.mNumber>1.0f){mToken.mNumber=1.0f;}uint8_tvalue=nsStyleUtil::FloatToColorComponent(mToken.mNumber);// Need to compare to something slightly larger// than 0.5 due to floating point inaccuracies.NS_ASSERTION(fabs(255.0f*mToken.mNumber-value)<=0.51f,"FloatToColorComponent did something weird");if(!ExpectSymbol(')',true)){REPORT_UNEXPECTED_TOKEN(PEExpectedCloseParen);returnfalse;}aOpacity=value;returntrue;}#ifdef MOZ_XULboolCSSParserImpl::ParseTreePseudoElement(nsAtomList**aPseudoElementArgs){// The argument to a tree pseudo-element is a sequence of identifiers// that are either space- or comma-separated. (Was the intent to// allow only comma-separated? That's not what was done.)nsCSSSelectorfakeSelector;// so we can reuse AddPseudoClasswhile(!ExpectSymbol(')',true)){if(!GetToken(true)){returnfalse;}if(eCSSToken_Ident==mToken.mType){fakeSelector.AddClass(mToken.mIdent);}elseif(!mToken.IsSymbol(',')){UngetToken();SkipUntil(')');returnfalse;}}*aPseudoElementArgs=fakeSelector.mClassList;fakeSelector.mClassList=nullptr;returntrue;}#endif//----------------------------------------------------------------------boolCSSParserImpl::ParseDeclaration(css::Declaration*aDeclaration,uint32_taFlags,boolaMustCallValueAppended,bool*aChanged,nsCSSContextTypeaContext){NS_PRECONDITION(aContext==eCSSContext_General||aContext==eCSSContext_Page,"Must be page or general context");boolcheckForBraces=(aFlags&eParseDeclaration_InBraces)!=0;mTempData.AssertInitialState();// Get property namensCSSToken*tk=&mToken;nsAutoStringpropertyName;for(;;){if(!GetToken(true)){if(checkForBraces){REPORT_UNEXPECTED_EOF(PEDeclEndEOF);}returnfalse;}if(eCSSToken_Ident==tk->mType){propertyName=tk->mIdent;// grab the ident before the ExpectSymbol trashes the tokenif(!ExpectSymbol(':',true)){REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon);REPORT_UNEXPECTED(PEDeclDropped);OUTPUT_ERROR();returnfalse;}break;}if(tk->IsSymbol(';')){// dangling semicolons are skippedcontinue;}if(!tk->IsSymbol('}')){REPORT_UNEXPECTED_TOKEN(PEParseDeclarationDeclExpected);REPORT_UNEXPECTED(PEDeclSkipped);OUTPUT_ERROR();}// Not a declaration...UngetToken();returnfalse;}// Don't report property parse errors if we're inside a failing @supports// rule.nsAutoSuppressErrorssuppressErrors(this,mInFailingSupportsRule);// Map property name to its ID and then parse the propertynsCSSPropertypropID=nsCSSProps::LookupProperty(propertyName,nsCSSProps::eEnabled);if(eCSSProperty_UNKNOWN==propID||(aContext==eCSSContext_Page&&!nsCSSProps::PropHasFlags(propID,CSS_PROPERTY_APPLIES_TO_PAGE_RULE))){// unknown propertyif(!NonMozillaVendorIdentifier(propertyName)){REPORT_UNEXPECTED_P(PEUnknownProperty,propertyName);REPORT_UNEXPECTED(PEDeclDropped);OUTPUT_ERROR();}returnfalse;}if(!ParseProperty(propID)){// XXX Much better to put stuff in the value parsers instead...REPORT_UNEXPECTED_P(PEValueParsingError,propertyName);REPORT_UNEXPECTED(PEDeclDropped);OUTPUT_ERROR();mTempData.ClearProperty(propID);mTempData.AssertInitialState();returnfalse;}CLEAR_ERROR();// Look for "!important".PriorityParsingStatusstatus;if((aFlags&eParseDeclaration_AllowImportant)!=0){status=ParsePriority();}else{status=ePriority_None;}// Look for a semicolon or close brace.if(status!=ePriority_Error){if(!GetToken(true)){// EOF is always ok}elseif(mToken.IsSymbol(';')){// semicolon is always ok}elseif(mToken.IsSymbol('}')){// brace is ok if checkForBraces, but don't eat itUngetToken();if(!checkForBraces){status=ePriority_Error;}}else{UngetToken();status=ePriority_Error;}}if(status==ePriority_Error){if(checkForBraces){REPORT_UNEXPECTED_TOKEN(PEBadDeclOrRuleEnd2);}else{REPORT_UNEXPECTED_TOKEN(PEBadDeclEnd);}REPORT_UNEXPECTED(PEDeclDropped);OUTPUT_ERROR();mTempData.ClearProperty(propID);mTempData.AssertInitialState();returnfalse;}*aChanged|=mData.TransferFromBlock(mTempData,propID,status==ePriority_Important,false,aMustCallValueAppended,aDeclaration);returntrue;}staticconstnsCSSPropertykBorderTopIDs[]={eCSSProperty_border_top_width,eCSSProperty_border_top_style,eCSSProperty_border_top_color};staticconstnsCSSPropertykBorderRightIDs[]={eCSSProperty_border_right_width_value,eCSSProperty_border_right_style_value,eCSSProperty_border_right_color_value,eCSSProperty_border_right_width,eCSSProperty_border_right_style,eCSSProperty_border_right_color};staticconstnsCSSPropertykBorderBottomIDs[]={eCSSProperty_border_bottom_width,eCSSProperty_border_bottom_style,eCSSProperty_border_bottom_color};staticconstnsCSSPropertykBorderLeftIDs[]={eCSSProperty_border_left_width_value,eCSSProperty_border_left_style_value,eCSSProperty_border_left_color_value,eCSSProperty_border_left_width,eCSSProperty_border_left_style,eCSSProperty_border_left_color};staticconstnsCSSPropertykBorderStartIDs[]={eCSSProperty_border_start_width_value,eCSSProperty_border_start_style_value,eCSSProperty_border_start_color_value,eCSSProperty_border_start_width,eCSSProperty_border_start_style,eCSSProperty_border_start_color};staticconstnsCSSPropertykBorderEndIDs[]={eCSSProperty_border_end_width_value,eCSSProperty_border_end_style_value,eCSSProperty_border_end_color_value,eCSSProperty_border_end_width,eCSSProperty_border_end_style,eCSSProperty_border_end_color};staticconstnsCSSPropertykColumnRuleIDs[]={eCSSProperty__moz_column_rule_width,eCSSProperty__moz_column_rule_style,eCSSProperty__moz_column_rule_color};boolCSSParserImpl::ParseEnum(nsCSSValue&aValue,constint32_taKeywordTable[]){nsSubstring*ident=NextIdent();if(nullptr==ident){returnfalse;}nsCSSKeywordkeyword=nsCSSKeywords::LookupKeyword(*ident);if(eCSSKeyword_UNKNOWN<keyword){int32_tvalue;if(nsCSSProps::FindKeyword(keyword,aKeywordTable,value)){aValue.SetIntValue(value,eCSSUnit_Enumerated);returntrue;}}// Put the unknown identifier back and returnUngetToken();returnfalse;}structUnitInfo{charname[6];// needs to be long enough for the longest unit, with// terminating null.uint32_tlength;nsCSSUnitunit;int32_ttype;};#define STR_WITH_LEN(_str) \ _str, sizeof(_str) - 1constUnitInfoUnitData[]={{STR_WITH_LEN("px"),eCSSUnit_Pixel,VARIANT_LENGTH},{STR_WITH_LEN("em"),eCSSUnit_EM,VARIANT_LENGTH},{STR_WITH_LEN("ex"),eCSSUnit_XHeight,VARIANT_LENGTH},{STR_WITH_LEN("pt"),eCSSUnit_Point,VARIANT_LENGTH},{STR_WITH_LEN("in"),eCSSUnit_Inch,VARIANT_LENGTH},{STR_WITH_LEN("cm"),eCSSUnit_Centimeter,VARIANT_LENGTH},{STR_WITH_LEN("ch"),eCSSUnit_Char,VARIANT_LENGTH},{STR_WITH_LEN("rem"),eCSSUnit_RootEM,VARIANT_LENGTH},{STR_WITH_LEN("mm"),eCSSUnit_Millimeter,VARIANT_LENGTH},{STR_WITH_LEN("mozmm"),eCSSUnit_PhysicalMillimeter,VARIANT_LENGTH},{STR_WITH_LEN("vw"),eCSSUnit_ViewportWidth,VARIANT_LENGTH},{STR_WITH_LEN("vh"),eCSSUnit_ViewportHeight,VARIANT_LENGTH},{STR_WITH_LEN("vmin"),eCSSUnit_ViewportMin,VARIANT_LENGTH},{STR_WITH_LEN("vmax"),eCSSUnit_ViewportMax,VARIANT_LENGTH},{STR_WITH_LEN("pc"),eCSSUnit_Pica,VARIANT_LENGTH},{STR_WITH_LEN("deg"),eCSSUnit_Degree,VARIANT_ANGLE},{STR_WITH_LEN("grad"),eCSSUnit_Grad,VARIANT_ANGLE},{STR_WITH_LEN("rad"),eCSSUnit_Radian,VARIANT_ANGLE},{STR_WITH_LEN("turn"),eCSSUnit_Turn,VARIANT_ANGLE},{STR_WITH_LEN("hz"),eCSSUnit_Hertz,VARIANT_FREQUENCY},{STR_WITH_LEN("khz"),eCSSUnit_Kilohertz,VARIANT_FREQUENCY},{STR_WITH_LEN("s"),eCSSUnit_Seconds,VARIANT_TIME},{STR_WITH_LEN("ms"),eCSSUnit_Milliseconds,VARIANT_TIME}};#undef STR_WITH_LENboolCSSParserImpl::TranslateDimension(nsCSSValue&aValue,int32_taVariantMask,floataNumber,constnsString&aUnit){nsCSSUnitunits;int32_ttype=0;if(!aUnit.IsEmpty()){uint32_ti;for(i=0;i<ArrayLength(UnitData);++i){if(aUnit.LowerCaseEqualsASCII(UnitData[i].name,UnitData[i].length)){units=UnitData[i].unit;type=UnitData[i].type;break;}}if(!mViewportUnitsEnabled&&(eCSSUnit_ViewportWidth==units||eCSSUnit_ViewportHeight==units||eCSSUnit_ViewportMin==units||eCSSUnit_ViewportMax==units)){// Viewport units aren't allowed right now, probably because we're// inside an @page declaration. Fail.returnfalse;}if(i==ArrayLength(UnitData)){// Unknown unitreturnfalse;}}else{// Must be a zero number...NS_ASSERTION(0==aNumber,"numbers without units must be 0");if((VARIANT_LENGTH&aVariantMask)!=0){units=eCSSUnit_Pixel;type=VARIANT_LENGTH;}elseif((VARIANT_ANGLE&aVariantMask)!=0){NS_ASSERTION(aVariantMask&VARIANT_ZERO_ANGLE,"must have allowed zero angle");units=eCSSUnit_Degree;type=VARIANT_ANGLE;}else{NS_ERROR("Variant mask does not include dimension; why were we called?");returnfalse;}}if((type&aVariantMask)!=0){aValue.SetFloatValue(aNumber,units);returntrue;}returnfalse;}// Note that this does include VARIANT_CALC, which is numeric. This is// because calc() parsing, as proposed, drops range restrictions inside// the calc() expression and clamps the result of the calculation to the// range.#define VARIANT_ALL_NONNUMERIC \ VARIANT_KEYWORD | \ VARIANT_COLOR | \ VARIANT_URL | \ VARIANT_STRING | \ VARIANT_COUNTER | \ VARIANT_ATTR | \ VARIANT_IDENTIFIER | \ VARIANT_IDENTIFIER_NO_INHERIT | \ VARIANT_AUTO | \ VARIANT_INHERIT | \ VARIANT_NONE | \ VARIANT_NORMAL | \ VARIANT_SYSFONT | \ VARIANT_GRADIENT | \ VARIANT_TIMING_FUNCTION | \ VARIANT_ALL | \ VARIANT_CALC// Note that callers passing VARIANT_CALC in aVariantMask will get// full-range parsing inside the calc() expression, and the code that// computes the calc will be required to clamp the resulting value to an// appropriate range.boolCSSParserImpl::ParseNonNegativeVariant(nsCSSValue&aValue,int32_taVariantMask,constint32_taKeywordTable[]){// The variant mask must only contain non-numeric variants or the ones// that we specifically handle.NS_ABORT_IF_FALSE((aVariantMask&~(VARIANT_ALL_NONNUMERIC|VARIANT_NUMBER|VARIANT_LENGTH|VARIANT_PERCENT|VARIANT_INTEGER))==0,"need to update code below to handle additional variants");if(ParseVariant(aValue,aVariantMask,aKeywordTable)){if(eCSSUnit_Number==aValue.GetUnit()||aValue.IsLengthUnit()){if(aValue.GetFloatValue()<0){UngetToken();returnfalse;}}elseif(aValue.GetUnit()==eCSSUnit_Percent){if(aValue.GetPercentValue()<0){UngetToken();returnfalse;}}elseif(aValue.GetUnit()==eCSSUnit_Integer){if(aValue.GetIntValue()<0){UngetToken();returnfalse;}}returntrue;}returnfalse;}// Note that callers passing VARIANT_CALC in aVariantMask will get// full-range parsing inside the calc() expression, and the code that// computes the calc will be required to clamp the resulting value to an// appropriate range.boolCSSParserImpl::ParseOneOrLargerVariant(nsCSSValue&aValue,int32_taVariantMask,constint32_taKeywordTable[]){// The variant mask must only contain non-numeric variants or the ones// that we specifically handle.NS_ABORT_IF_FALSE((aVariantMask&~(VARIANT_ALL_NONNUMERIC|VARIANT_NUMBER|VARIANT_INTEGER))==0,"need to update code below to handle additional variants");if(ParseVariant(aValue,aVariantMask,aKeywordTable)){if(aValue.GetUnit()==eCSSUnit_Integer){if(aValue.GetIntValue()<1){UngetToken();returnfalse;}}elseif(eCSSUnit_Number==aValue.GetUnit()){if(aValue.GetFloatValue()<1.0f){UngetToken();returnfalse;}}returntrue;}returnfalse;}// Assigns to aValue iff it returns true.boolCSSParserImpl::ParseVariant(nsCSSValue&aValue,int32_taVariantMask,constint32_taKeywordTable[]){NS_ASSERTION(!(mHashlessColorQuirk&&(aVariantMask&VARIANT_COLOR))||!(aVariantMask&VARIANT_NUMBER),"can't distinguish colors from numbers");NS_ASSERTION(!(mHashlessColorQuirk&&(aVariantMask&VARIANT_COLOR))||!(mUnitlessLengthQuirk&&(aVariantMask&VARIANT_LENGTH)),"can't distinguish colors from lengths");NS_ASSERTION(!(mUnitlessLengthQuirk&&(aVariantMask&VARIANT_LENGTH))||!(aVariantMask&VARIANT_NUMBER),"can't distinguish lengths from numbers");NS_ABORT_IF_FALSE(!(aVariantMask&VARIANT_IDENTIFIER)||!(aVariantMask&VARIANT_IDENTIFIER_NO_INHERIT),"must not set both VARIANT_IDENTIFIER and ""VARIANT_IDENTIFIER_NO_INHERIT");if(!GetToken(true)){returnfalse;}nsCSSToken*tk=&mToken;if(((aVariantMask&(VARIANT_AHK|VARIANT_NORMAL|VARIANT_NONE|VARIANT_ALL))!=0)&&(eCSSToken_Ident==tk->mType)){nsCSSKeywordkeyword=nsCSSKeywords::LookupKeyword(tk->mIdent);if(eCSSKeyword_UNKNOWN<keyword){// known keywordif((aVariantMask&VARIANT_AUTO)!=0){if(eCSSKeyword_auto==keyword){aValue.SetAutoValue();returntrue;}}if((aVariantMask&VARIANT_INHERIT)!=0){// XXX Should we check IsParsingCompoundProperty, or do all// callers handle it? (Not all callers set it, though, since// they want the quirks that are disabled by setting it.)if(eCSSKeyword_inherit==keyword){aValue.SetInheritValue();returntrue;}elseif(eCSSKeyword__moz_initial==keyword||eCSSKeyword_initial==keyword){// anything that can inherit can also take an initial val.aValue.SetInitialValue();returntrue;}}if((aVariantMask&VARIANT_NONE)!=0){if(eCSSKeyword_none==keyword){aValue.SetNoneValue();returntrue;}}if((aVariantMask&VARIANT_ALL)!=0){if(eCSSKeyword_all==keyword){aValue.SetAllValue();returntrue;}}if((aVariantMask&VARIANT_NORMAL)!=0){if(eCSSKeyword_normal==keyword){aValue.SetNormalValue();returntrue;}}if((aVariantMask&VARIANT_SYSFONT)!=0){if(eCSSKeyword__moz_use_system_font==keyword&&!IsParsingCompoundProperty()){aValue.SetSystemFontValue();returntrue;}}if((aVariantMask&VARIANT_KEYWORD)!=0){int32_tvalue;if(nsCSSProps::FindKeyword(keyword,aKeywordTable,value)){aValue.SetIntValue(value,eCSSUnit_Enumerated);returntrue;}}}}// Check VARIANT_NUMBER and VARIANT_INTEGER before VARIANT_LENGTH or// VARIANT_ZERO_ANGLE.if(((aVariantMask&VARIANT_NUMBER)!=0)&&(eCSSToken_Number==tk->mType)){aValue.SetFloatValue(tk->mNumber,eCSSUnit_Number);returntrue;}if(((aVariantMask&VARIANT_INTEGER)!=0)&&(eCSSToken_Number==tk->mType)&&tk->mIntegerValid){aValue.SetIntValue(tk->mInteger,eCSSUnit_Integer);returntrue;}if(((aVariantMask&(VARIANT_LENGTH|VARIANT_ANGLE|VARIANT_FREQUENCY|VARIANT_TIME))!=0&&eCSSToken_Dimension==tk->mType)||((aVariantMask&(VARIANT_LENGTH|VARIANT_ZERO_ANGLE))!=0&&eCSSToken_Number==tk->mType&&tk->mNumber==0.0f)){if(((aVariantMask&VARIANT_POSITIVE_DIMENSION)!=0&&tk->mNumber<=0.0)||((aVariantMask&VARIANT_NONNEGATIVE_DIMENSION)!=0&&tk->mNumber<0.0)){UngetToken();returnfalse;}if(TranslateDimension(aValue,aVariantMask,tk->mNumber,tk->mIdent)){returntrue;}// Put the token back; we didn't parse it, so we shouldn't consume itUngetToken();returnfalse;}if(((aVariantMask&VARIANT_PERCENT)!=0)&&(eCSSToken_Percentage==tk->mType)){aValue.SetPercentValue(tk->mNumber);returntrue;}if(mUnitlessLengthQuirk){// NONSTANDARD: Nav interprets unitless numbers as pxif(((aVariantMask&VARIANT_LENGTH)!=0)&&(eCSSToken_Number==tk->mType)){aValue.SetFloatValue(tk->mNumber,eCSSUnit_Pixel);returntrue;}}if(IsSVGMode()&&!IsParsingCompoundProperty()){// STANDARD: SVG Spec states that lengths and coordinates can be unitless// in which case they default to user-units (1 px = 1 user unit)if(((aVariantMask&VARIANT_LENGTH)!=0)&&(eCSSToken_Number==tk->mType)){aValue.SetFloatValue(tk->mNumber,eCSSUnit_Pixel);returntrue;}}if(((aVariantMask&VARIANT_URL)!=0)&&eCSSToken_URL==tk->mType){SetValueToURL(aValue,tk->mIdent);returntrue;}if((aVariantMask&VARIANT_GRADIENT)!=0&&eCSSToken_Function==tk->mType){// a generated gradientnsDependentStringtmp(tk->mIdent,0);boolisLegacy=false;if(StringBeginsWith(tmp,NS_LITERAL_STRING("-moz-"))){tmp.Rebind(tmp,5);isLegacy=true;}boolisRepeating=false;if(StringBeginsWith(tmp,NS_LITERAL_STRING("repeating-"))){tmp.Rebind(tmp,10);isRepeating=true;}if(tmp.LowerCaseEqualsLiteral("linear-gradient")){returnParseLinearGradient(aValue,isRepeating,isLegacy);}if(tmp.LowerCaseEqualsLiteral("radial-gradient")){returnParseRadialGradient(aValue,isRepeating,isLegacy);}}if((aVariantMask&VARIANT_IMAGE_RECT)!=0&&eCSSToken_Function==tk->mType&&tk->mIdent.LowerCaseEqualsLiteral("-moz-image-rect")){returnParseImageRect(aValue);}if((aVariantMask&VARIANT_ELEMENT)!=0&&eCSSToken_Function==tk->mType&&tk->mIdent.LowerCaseEqualsLiteral("-moz-element")){returnParseElement(aValue);}if((aVariantMask&VARIANT_COLOR)!=0){if(mHashlessColorQuirk||// NONSTANDARD: Nav interprets 'xxyyzz' values even without '#' prefix(eCSSToken_ID==tk->mType)||(eCSSToken_Hash==tk->mType)||(eCSSToken_Ident==tk->mType)||((eCSSToken_Function==tk->mType)&&(tk->mIdent.LowerCaseEqualsLiteral("rgb")||tk->mIdent.LowerCaseEqualsLiteral("hsl")||tk->mIdent.LowerCaseEqualsLiteral("-moz-rgba")||tk->mIdent.LowerCaseEqualsLiteral("-moz-hsla")||tk->mIdent.LowerCaseEqualsLiteral("rgba")||tk->mIdent.LowerCaseEqualsLiteral("hsla")))){// Put token back so that parse color can get itUngetToken();if(ParseColor(aValue)){returntrue;}returnfalse;}}if(((aVariantMask&VARIANT_STRING)!=0)&&(eCSSToken_String==tk->mType)){nsAutoStringbuffer;buffer.Append(tk->mIdent);aValue.SetStringValue(buffer,eCSSUnit_String);returntrue;}if(((aVariantMask&(VARIANT_IDENTIFIER|VARIANT_IDENTIFIER_NO_INHERIT))!=0)&&(eCSSToken_Ident==tk->mType)&&((aVariantMask&VARIANT_IDENTIFIER)!=0||!(tk->mIdent.LowerCaseEqualsLiteral("inherit")||tk->mIdent.LowerCaseEqualsLiteral("initial")))){aValue.SetStringValue(tk->mIdent,eCSSUnit_Ident);returntrue;}if(((aVariantMask&VARIANT_COUNTER)!=0)&&(eCSSToken_Function==tk->mType)&&(tk->mIdent.LowerCaseEqualsLiteral("counter")||tk->mIdent.LowerCaseEqualsLiteral("counters"))){returnParseCounter(aValue);}if(((aVariantMask&VARIANT_ATTR)!=0)&&(eCSSToken_Function==tk->mType)&&tk->mIdent.LowerCaseEqualsLiteral("attr")){if(!ParseAttr(aValue)){SkipUntil(')');returnfalse;}returntrue;}if(((aVariantMask&VARIANT_TIMING_FUNCTION)!=0)&&(eCSSToken_Function==tk->mType)){if(tk->mIdent.LowerCaseEqualsLiteral("cubic-bezier")){if(!ParseTransitionTimingFunctionValues(aValue)){SkipUntil(')');returnfalse;}returntrue;}if(tk->mIdent.LowerCaseEqualsLiteral("steps")){if(!ParseTransitionStepTimingFunctionValues(aValue)){SkipUntil(')');returnfalse;}returntrue;}}if((aVariantMask&VARIANT_CALC)&&(eCSSToken_Function==tk->mType)&&(tk->mIdent.LowerCaseEqualsLiteral("calc")||tk->mIdent.LowerCaseEqualsLiteral("-moz-calc"))){// calc() currently allows only lengths and percents inside it.returnParseCalc(aValue,aVariantMask&VARIANT_LP);}UngetToken();returnfalse;}boolCSSParserImpl::ParseCounter(nsCSSValue&aValue){nsCSSUnitunit=(mToken.mIdent.LowerCaseEqualsLiteral("counter")?eCSSUnit_Counter:eCSSUnit_Counters);// A non-iterative for loop to break out when an error occurs.for(;;){if(!GetToken(true)){break;}if(eCSSToken_Ident!=mToken.mType){UngetToken();break;}nsRefPtr<nsCSSValue::Array>val=nsCSSValue::Array::Create(unit==eCSSUnit_Counter?2:3);val->Item(0).SetStringValue(mToken.mIdent,eCSSUnit_Ident);if(eCSSUnit_Counters==unit){// must have a comma and then a separator stringif(!ExpectSymbol(',',true)||!GetToken(true)){break;}if(eCSSToken_String!=mToken.mType){UngetToken();break;}val->Item(1).SetStringValue(mToken.mIdent,eCSSUnit_String);}// get optional typeint32_ttype=NS_STYLE_LIST_STYLE_DECIMAL;if(ExpectSymbol(',',true)){if(!GetToken(true)){break;}nsCSSKeywordkeyword;if(eCSSToken_Ident!=mToken.mType||(keyword=nsCSSKeywords::LookupKeyword(mToken.mIdent))==eCSSKeyword_UNKNOWN||!nsCSSProps::FindKeyword(keyword,nsCSSProps::kListStyleKTable,type)){UngetToken();break;}}int32_ttypeItem=eCSSUnit_Counters==unit?2:1;val->Item(typeItem).SetIntValue(type,eCSSUnit_Enumerated);if(!ExpectSymbol(')',true)){break;}aValue.SetArrayValue(val,unit);returntrue;}SkipUntil(')');returnfalse;}boolCSSParserImpl::ParseAttr(nsCSSValue&aValue){if(!GetToken(true)){returnfalse;}nsAutoStringattr;if(eCSSToken_Ident==mToken.mType){// attr name or namespacensAutoStringholdIdent(mToken.mIdent);if(ExpectSymbol('|',false)){// namespaceint32_tnameSpaceID=GetNamespaceIdForPrefix(holdIdent);if(nameSpaceID==kNameSpaceID_Unknown){returnfalse;}attr.AppendInt(nameSpaceID,10);attr.Append(PRUnichar('|'));if(!GetToken(false)){REPORT_UNEXPECTED_EOF(PEAttributeNameEOF);returnfalse;}if(eCSSToken_Ident==mToken.mType){attr.Append(mToken.mIdent);}else{REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected);UngetToken();returnfalse;}}else{// no namespaceattr=holdIdent;}}elseif(mToken.IsSymbol('*')){// namespace wildcard// Wildcard namespace makes no sense here and is not allowedREPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected);UngetToken();returnfalse;}elseif(mToken.IsSymbol('|')){// explicit NO namespaceif(!GetToken(false)){REPORT_UNEXPECTED_EOF(PEAttributeNameEOF);returnfalse;}if(eCSSToken_Ident==mToken.mType){attr.Append(mToken.mIdent);}else{REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected);UngetToken();returnfalse;}}else{REPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected);UngetToken();returnfalse;}if(!ExpectSymbol(')',true)){returnfalse;}aValue.SetStringValue(attr,eCSSUnit_Attr);returntrue;}boolCSSParserImpl::SetValueToURL(nsCSSValue&aValue,constnsString&aURL){if(!mSheetPrincipal){NS_NOTREACHED("Codepaths that expect to parse URLs MUST pass in an ""origin principal");returnfalse;}nsRefPtr<nsStringBuffer>buffer(nsCSSValue::BufferFromString(aURL));// Note: urlVal retains its own reference to |buffer|.mozilla::css::URLValue*urlVal=newmozilla::css::URLValue(buffer,mBaseURI,mSheetURI,mSheetPrincipal);aValue.SetURLValue(urlVal);returntrue;}/** * Parse the arguments of -moz-image-rect() function. * -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>) */boolCSSParserImpl::ParseImageRect(nsCSSValue&aImage){// A non-iterative for loop to break out when an error occurs.for(;;){nsCSSValuenewFunction;staticconstuint32_tkNumArgs=5;nsCSSValue::Array*func=newFunction.InitFunction(eCSSKeyword__moz_image_rect,kNumArgs);// func->Item(0) is reserved for the function name.nsCSSValue&url=func->Item(1);nsCSSValue&top=func->Item(2);nsCSSValue&right=func->Item(3);nsCSSValue&bottom=func->Item(4);nsCSSValue&left=func->Item(5);nsAutoStringurlString;if(!ParseURLOrString(urlString)||!SetValueToURL(url,urlString)||!ExpectSymbol(',',true)){break;}staticconstint32_tVARIANT_SIDE=VARIANT_NUMBER|VARIANT_PERCENT;if(!ParseNonNegativeVariant(top,VARIANT_SIDE,nullptr)||!ExpectSymbol(',',true)||!ParseNonNegativeVariant(right,VARIANT_SIDE,nullptr)||!ExpectSymbol(',',true)||!ParseNonNegativeVariant(bottom,VARIANT_SIDE,nullptr)||!ExpectSymbol(',',true)||!ParseNonNegativeVariant(left,VARIANT_SIDE,nullptr)||!ExpectSymbol(')',true))break;aImage=newFunction;returntrue;}SkipUntil(')');returnfalse;}// <element>: -moz-element(# <element_id> )boolCSSParserImpl::ParseElement(nsCSSValue&aValue){// A non-iterative for loop to break out when an error occurs.for(;;){if(!GetToken(true))break;if(mToken.mType==eCSSToken_ID){aValue.SetStringValue(mToken.mIdent,eCSSUnit_Element);}else{UngetToken();break;}if(!ExpectSymbol(')',true))break;returntrue;}// If we detect a syntax error, we must match the opening parenthesis of the// function with the closing parenthesis and skip all the tokens in between.SkipUntil(')');returnfalse;}#ifdef MOZ_FLEXBOX// flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]boolCSSParserImpl::ParseFlex(){// First check for inherit / initialnsCSSValuetmpVal;if(ParseVariant(tmpVal,VARIANT_INHERIT,nullptr)){AppendValue(eCSSProperty_flex_grow,tmpVal);AppendValue(eCSSProperty_flex_shrink,tmpVal);AppendValue(eCSSProperty_flex_basis,tmpVal);returntrue;}// Next, check for 'none' == '0 0 auto'if(ParseVariant(tmpVal,VARIANT_NONE,nullptr)){AppendValue(eCSSProperty_flex_grow,nsCSSValue(0.0f,eCSSUnit_Number));AppendValue(eCSSProperty_flex_shrink,nsCSSValue(0.0f,eCSSUnit_Number));AppendValue(eCSSProperty_flex_basis,nsCSSValue(eCSSUnit_Auto));returntrue;}// OK, try parsing our value as individual per-subproperty components:// [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]// Each subproperty has a default value that it takes when it's omitted in a// "flex" shorthand value. These default values are *only* for the shorthand// syntax -- they're distinct from the subproperties' own initial values. We// start with each subproperty at its default, as if we had "flex: 1 1 0%".nsCSSValueflexGrow(1.0f,eCSSUnit_Number);nsCSSValueflexShrink(1.0f,eCSSUnit_Number);nsCSSValueflexBasis(0.0f,eCSSUnit_Percent);// OVERVIEW OF PARSING STRATEGY:// =============================// a) Parse the first component as either flex-basis or flex-grow.// b) If it wasn't flex-grow, parse the _next_ component as flex-grow.// c) Now we've just parsed flex-grow -- so try parsing the next thing as// flex-shrink.// d) Finally: If we didn't get flex-basis at the beginning, try to parse// it now, at the end.//// More details in each section below.uint32_tflexBasisVariantMask=(nsCSSProps::ParserVariant(eCSSProperty_flex_basis)&~(VARIANT_INHERIT));// (a) Parse first component. It can be either be a 'flex-basis' value or a// 'flex-grow' value, so we use the flex-basis-specific variant mask, along// with VARIANT_NUMBER to accept 'flex-grow' values.//// NOTE: if we encounter unitless 0 here, we *must* interpret it as a// 'flex-grow' value (a number), *not* as a 'flex-basis' value (a length).// Conveniently, that's the behavior this combined variant-mask gives us --// it'll treat unitless 0 as a number. The flexbox spec requires this:// "a unitless zero that is not already preceded by two flex factors must be// interpreted as a flex factor.if(!ParseNonNegativeVariant(tmpVal,flexBasisVariantMask|VARIANT_NUMBER,nsCSSProps::kWidthKTable)){// First component was not a valid flex-basis or flex-grow value. Fail.returnfalse;}// Record what we just parsed as either flex-basis or flex-grow:boolwasFirstComponentFlexBasis=(tmpVal.GetUnit()!=eCSSUnit_Number);(wasFirstComponentFlexBasis?flexBasis:flexGrow)=tmpVal;// (b) If we didn't get flex-grow yet, parse _next_ component as flex-grow.booldoneParsing=false;if(wasFirstComponentFlexBasis){if(ParseNonNegativeVariant(tmpVal,VARIANT_NUMBER,nullptr)){flexGrow=tmpVal;}else{// Failed to parse anything after our flex-basis -- that's fine. We can// skip the remaining parsing.doneParsing=true;}}if(!doneParsing){// (c) OK -- the last thing we parsed was flex-grow, so look for a// flex-shrink in the next position.if(ParseNonNegativeVariant(tmpVal,VARIANT_NUMBER,nullptr)){flexShrink=tmpVal;}// d) Finally: If we didn't get flex-basis at the beginning, try to parse// it now, at the end.//// NOTE: If we encounter unitless 0 in this final position, we'll parse it// as a 'flex-basis' value. That's OK, because we know it must have// been "preceded by 2 flex factors" (justification below), which gets us// out of the spec's requirement of otherwise having to treat unitless 0// as a flex factor.//// JUSTIFICATION: How do we know that a unitless 0 here must have been// preceded by 2 flex factors? Well, suppose we had a unitless 0 that// was preceded by only 1 flex factor. Then, we would have already// accepted this unitless 0 as the 'flex-shrink' value, up above (since// it's a valid flex-shrink value), and we'd have moved on to the next// token (if any). And of course, if we instead had a unitless 0 preceded// by *no* flex factors (if it were the first token), we would've already// parsed it in our very first call to ParseNonNegativeVariant(). So, any// unitless 0 encountered here *must* have been preceded by 2 flex factors.if(!wasFirstComponentFlexBasis&&ParseNonNegativeVariant(tmpVal,flexBasisVariantMask,nsCSSProps::kWidthKTable)){flexBasis=tmpVal;}}AppendValue(eCSSProperty_flex_grow,flexGrow);AppendValue(eCSSProperty_flex_shrink,flexShrink);AppendValue(eCSSProperty_flex_basis,flexBasis);returntrue;}#endif// <color-stop> : <color> [ <percentage> | <length> ]?boolCSSParserImpl::ParseColorStop(nsCSSValueGradient*aGradient){nsCSSValueGradientStop*stop=aGradient->mStops.AppendElement();if(!ParseVariant(stop->mColor,VARIANT_COLOR,nullptr)){returnfalse;}// Stop positions do not have to fall between the starting-point and// ending-point, so we don't use ParseNonNegativeVariant.if(!ParseVariant(stop->mLocation,VARIANT_LP|VARIANT_CALC,nullptr)){stop->mLocation.SetNoneValue();}returntrue;}// <gradient>// : linear-gradient( <linear-gradient-line>? <color-stops> ')'// | radial-gradient( <radial-gradient-line>? <color-stops> ')'//// <linear-gradient-line> : [ to [left | right] || [top | bottom] ] ,// | <legacy-gradient-line>// <radial-gradient-line> : [ <shape> || <size> ] [ at <position> ]? ,// | [ at <position> ] ,// | <legacy-gradient-line>? <legacy-shape-size>?// <shape> : circle | ellipse// <size> : closest-side | closest-corner | farthest-side | farthest-corner// | <length> | [<length> | <percentage>]{2}//// <legacy-gradient-line> : [ <position> || <angle>] ,//// <legacy-shape-size> : [ <shape> || <legacy-size> ] ,// <legacy-size> : closest-side | closest-corner | farthest-side// | farthest-corner | contain | cover//// <color-stops> : <color-stop> , <color-stop> [, <color-stop>]*boolCSSParserImpl::ParseLinearGradient(nsCSSValue&aValue,boolaIsRepeating,boolaIsLegacy){nsRefPtr<nsCSSValueGradient>cssGradient=newnsCSSValueGradient(false,aIsRepeating);if(!GetToken(true)){returnfalse;}if(mToken.mType==eCSSToken_Ident&&mToken.mIdent.LowerCaseEqualsLiteral("to")){// "to" syntax doesn't allow explicit "center"if(!ParseBoxPositionValues(cssGradient->mBgPos,false,false)){SkipUntil(')');returnfalse;}// [ to [left | right] || [top | bottom] ] ,constnsCSSValue&xValue=cssGradient->mBgPos.mXValue;constnsCSSValue&yValue=cssGradient->mBgPos.mYValue;if(xValue.GetUnit()!=eCSSUnit_Enumerated||!(xValue.GetIntValue()&(NS_STYLE_BG_POSITION_LEFT|NS_STYLE_BG_POSITION_CENTER|NS_STYLE_BG_POSITION_RIGHT))||yValue.GetUnit()!=eCSSUnit_Enumerated||!(yValue.GetIntValue()&(NS_STYLE_BG_POSITION_TOP|NS_STYLE_BG_POSITION_CENTER|NS_STYLE_BG_POSITION_BOTTOM))){SkipUntil(')');returnfalse;}if(!ExpectSymbol(',',true)){SkipUntil(')');returnfalse;}returnParseGradientColorStops(cssGradient,aValue);}if(!aIsLegacy){UngetToken();// <angle> ,if(ParseVariant(cssGradient->mAngle,VARIANT_ANGLE,nullptr)&&!ExpectSymbol(',',true)){SkipUntil(')');returnfalse;}returnParseGradientColorStops(cssGradient,aValue);}nsCSSTokenTypety=mToken.mType;nsStringid=mToken.mIdent;UngetToken();// <legacy-gradient-line>boolhaveGradientLine=IsLegacyGradientLine(ty,id);if(haveGradientLine){cssGradient->mIsLegacySyntax=true;boolhaveAngle=ParseVariant(cssGradient->mAngle,VARIANT_ANGLE,nullptr);// if we got an angle, we might now have a comma, ending the gradient-lineif(!haveAngle||!ExpectSymbol(',',true)){if(!ParseBoxPositionValues(cssGradient->mBgPos,false)){SkipUntil(')');returnfalse;}if(!ExpectSymbol(',',true)&&// if we didn't already get an angle, we might have one now,// otherwise it's an error(haveAngle||!ParseVariant(cssGradient->mAngle,VARIANT_ANGLE,nullptr)||// now we better have a comma!ExpectSymbol(',',true))){SkipUntil(')');returnfalse;}}}returnParseGradientColorStops(cssGradient,aValue);}boolCSSParserImpl::ParseRadialGradient(nsCSSValue&aValue,boolaIsRepeating,boolaIsLegacy){nsRefPtr<nsCSSValueGradient>cssGradient=newnsCSSValueGradient(true,aIsRepeating);// [ <shape> || <size> ]boolhaveShape=ParseVariant(cssGradient->GetRadialShape(),VARIANT_KEYWORD,nsCSSProps::kRadialGradientShapeKTable);boolhaveSize=ParseVariant(cssGradient->GetRadialSize(),VARIANT_KEYWORD,aIsLegacy?nsCSSProps::kRadialGradientLegacySizeKTable:nsCSSProps::kRadialGradientSizeKTable);if(haveSize){if(!haveShape){// <size> <shape>haveShape=ParseVariant(cssGradient->GetRadialShape(),VARIANT_KEYWORD,nsCSSProps::kRadialGradientShapeKTable);}}elseif(!aIsLegacy){// <length> | [<length> | <percentage>]{2}haveSize=ParseNonNegativeVariant(cssGradient->GetRadiusX(),VARIANT_LP,nullptr);if(haveSize){// vertical extent is optionalboolhaveYSize=ParseNonNegativeVariant(cssGradient->GetRadiusY(),VARIANT_LP,nullptr);if(!haveShape){nsCSSValueshapeValue;haveShape=ParseVariant(shapeValue,VARIANT_KEYWORD,nsCSSProps::kRadialGradientShapeKTable);}int32_tshape=cssGradient->GetRadialShape().GetUnit()==eCSSUnit_Enumerated?cssGradient->GetRadialShape().GetIntValue():-1;if(haveYSize?shape==NS_STYLE_GRADIENT_SHAPE_CIRCULAR:cssGradient->GetRadiusX().GetUnit()==eCSSUnit_Percent||shape==NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL){SkipUntil(')');returnfalse;}cssGradient->mIsExplicitSize=true;}}if((haveShape||haveSize)&&ExpectSymbol(',',true)){// [ <shape> || <size> ] ,returnParseGradientColorStops(cssGradient,aValue);}if(!GetToken(true)){returnfalse;}if(!aIsLegacy){if(mToken.mType==eCSSToken_Ident&&mToken.mIdent.LowerCaseEqualsLiteral("at")){// [ <shape> || <size> ]? at <position> ,if(!ParseBoxPositionValues(cssGradient->mBgPos,false)||!ExpectSymbol(',',true)){SkipUntil(')');returnfalse;}returnParseGradientColorStops(cssGradient,aValue);}// <color-stops> onlyUngetToken();returnParseGradientColorStops(cssGradient,aValue);}MOZ_ASSERT(!cssGradient->mIsExplicitSize);nsCSSTokenTypety=mToken.mType;nsStringid=mToken.mIdent;UngetToken();// <legacy-gradient-line>boolhaveGradientLine=false;// if we already encountered a shape or size,// we can not have a gradient-line in legacy syntaxif(!haveShape&&!haveSize){haveGradientLine=IsLegacyGradientLine(ty,id);}if(haveGradientLine){boolhaveAngle=ParseVariant(cssGradient->mAngle,VARIANT_ANGLE,nullptr);// if we got an angle, we might now have a comma, ending the gradient-lineif(!haveAngle||!ExpectSymbol(',',true)){if(!ParseBoxPositionValues(cssGradient->mBgPos,false)){SkipUntil(')');returnfalse;}if(!ExpectSymbol(',',true)&&// if we didn't already get an angle, we might have one now,// otherwise it's an error(haveAngle||!ParseVariant(cssGradient->mAngle,VARIANT_ANGLE,nullptr)||// now we better have a comma!ExpectSymbol(',',true))){SkipUntil(')');returnfalse;}}if(cssGradient->mAngle.GetUnit()!=eCSSUnit_None){cssGradient->mIsLegacySyntax=true;}}// radial gradients might have a shape and size here for legacy syntaxif(!haveShape&&!haveSize){haveShape=ParseVariant(cssGradient->GetRadialShape(),VARIANT_KEYWORD,nsCSSProps::kRadialGradientShapeKTable);haveSize=ParseVariant(cssGradient->GetRadialSize(),VARIANT_KEYWORD,nsCSSProps::kRadialGradientLegacySizeKTable);// could be in either orderif(!haveShape){haveShape=ParseVariant(cssGradient->GetRadialShape(),VARIANT_KEYWORD,nsCSSProps::kRadialGradientShapeKTable);}}if((haveShape||haveSize)&&!ExpectSymbol(',',true)){SkipUntil(')');returnfalse;}returnParseGradientColorStops(cssGradient,aValue);}boolCSSParserImpl::IsLegacyGradientLine(constnsCSSTokenType&aType,constnsString&aId){// N.B. ParseBoxPositionValues is not guaranteed to put back// everything it scanned if it fails, so we must only call it// if there is no alternative to consuming a <box-position>.// ParseVariant, as used here, will either succeed and consume// a single token, or fail and consume none, so we can be more// cavalier about calling it.boolhaveGradientLine=false;switch(aType){caseeCSSToken_Percentage:caseeCSSToken_Number:caseeCSSToken_Dimension:haveGradientLine=true;break;caseeCSSToken_Function:if(aId.LowerCaseEqualsLiteral("calc")||aId.LowerCaseEqualsLiteral("-moz-calc")){haveGradientLine=true;break;}// fall throughcaseeCSSToken_ID:caseeCSSToken_Hash:// this is a colorbreak;caseeCSSToken_Ident:{// This is only a gradient line if it's a box position keyword.nsCSSKeywordkw=nsCSSKeywords::LookupKeyword(aId);int32_tjunk;if(kw!=eCSSKeyword_UNKNOWN&&nsCSSProps::FindKeyword(kw,nsCSSProps::kBackgroundPositionKTable,junk)){haveGradientLine=true;}break;}default:// errorbreak;}returnhaveGradientLine;}boolCSSParserImpl::ParseGradientColorStops(nsCSSValueGradient*aGradient,nsCSSValue&aValue){// At least two color stops are requiredif(!ParseColorStop(aGradient)||!ExpectSymbol(',',true)||!ParseColorStop(aGradient)){SkipUntil(')');returnfalse;}// Additional color stopswhile(ExpectSymbol(',',true)){if(!ParseColorStop(aGradient)){SkipUntil(')');returnfalse;}}if(!ExpectSymbol(')',true)){SkipUntil(')');returnfalse;}aValue.SetGradientValue(aGradient);returntrue;}int32_tCSSParserImpl::ParseChoice(nsCSSValueaValues[],constnsCSSPropertyaPropIDs[],int32_taNumIDs){int32_tfound=0;nsAutoParseCompoundPropertycompound(this);int32_tloop;for(loop=0;loop<aNumIDs;loop++){// Try each property parser in orderint32_thadFound=found;int32_tindex;for(index=0;index<aNumIDs;index++){int32_tbit=1<<index;if((found&bit)==0){if(ParseSingleValueProperty(aValues[index],aPropIDs[index])){found|=bit;// It's more efficient to break since it will reset |hadFound|// to |found|. Furthermore, ParseListStyle depends on our going// through the properties in order for each value..break;}}}if(found==hadFound){// found nothing newbreak;}}if(0<found){if(1==found){// only first propertyif(eCSSUnit_Inherit==aValues[0].GetUnit()){// one inherit, all inheritfor(loop=1;loop<aNumIDs;loop++){aValues[loop].SetInheritValue();}found=((1<<aNumIDs)-1);}elseif(eCSSUnit_Initial==aValues[0].GetUnit()){// one initial, all initialfor(loop=1;loop<aNumIDs;loop++){aValues[loop].SetInitialValue();}found=((1<<aNumIDs)-1);}}else{// more than one value, verify no inherits or initialsfor(loop=0;loop<aNumIDs;loop++){if(eCSSUnit_Inherit==aValues[loop].GetUnit()){found=-1;break;}elseif(eCSSUnit_Initial==aValues[loop].GetUnit()){found=-1;break;}}}}returnfound;}voidCSSParserImpl::AppendValue(nsCSSPropertyaPropID,constnsCSSValue&aValue){mTempData.AddLonghandProperty(aPropID,aValue);}/** * Parse a "box" property. Box properties have 1 to 4 values. When less * than 4 values are provided a standard mapping is used to replicate * existing values. */boolCSSParserImpl::ParseBoxProperties(constnsCSSPropertyaPropIDs[]){// Get up to four values for the propertyint32_tcount=0;nsCSSRectresult;NS_FOR_CSS_SIDES(index){if(!ParseSingleValueProperty(result.*(nsCSSRect::sides[index]),aPropIDs[index])){break;}count++;}if((count==0)||(false==ExpectEndProperty())){returnfalse;}if(1<count){// verify no more than single inherit or initialNS_FOR_CSS_SIDES(index){nsCSSUnitunit=(result.*(nsCSSRect::sides[index])).GetUnit();if(eCSSUnit_Inherit==unit||eCSSUnit_Initial==unit){returnfalse;}}}// Provide missing values by replicating some of the values foundswitch(count){case1:// Make right == topresult.mRight=result.mTop;case2:// Make bottom == topresult.mBottom=result.mTop;case3:// Make left == rightresult.mLeft=result.mRight;}NS_FOR_CSS_SIDES(index){AppendValue(aPropIDs[index],result.*(nsCSSRect::sides[index]));}returntrue;}// Similar to ParseBoxProperties, except there is only one property// with the result as its value, not four. Requires values be nonnegative.boolCSSParserImpl::ParseGroupedBoxProperty(int32_taVariantMask,/** outparam */nsCSSValue&aValue){nsCSSRect&result=aValue.SetRectValue();int32_tcount=0;NS_FOR_CSS_SIDES(index){if(!ParseNonNegativeVariant(result.*(nsCSSRect::sides[index]),aVariantMask,nullptr)){break;}count++;}if(count==0){returnfalse;}// Provide missing values by replicating some of the values foundswitch(count){case1:// Make right == topresult.mRight=result.mTop;case2:// Make bottom == topresult.mBottom=result.mTop;case3:// Make left == rightresult.mLeft=result.mRight;}returntrue;}boolCSSParserImpl::ParseDirectionalBoxProperty(nsCSSPropertyaProperty,int32_taSourceType){constnsCSSProperty*subprops=nsCSSProps::SubpropertyEntryFor(aProperty);NS_ASSERTION(subprops[3]==eCSSProperty_UNKNOWN,"not box property with physical vs. logical cascading");nsCSSValuevalue;if(!ParseSingleValueProperty(value,subprops[0])||!ExpectEndProperty())returnfalse;AppendValue(subprops[0],value);nsCSSValuetypeVal(aSourceType,eCSSUnit_Enumerated);AppendValue(subprops[1],typeVal);AppendValue(subprops[2],typeVal);returntrue;}boolCSSParserImpl::ParseBoxCornerRadius(nsCSSPropertyaPropID){nsCSSValuedimenX,dimenY;// required first valueif(!ParseNonNegativeVariant(dimenX,VARIANT_HLP|VARIANT_CALC,nullptr))returnfalse;// optional second value (forbidden if first value is inherit/initial)if(dimenX.GetUnit()!=eCSSUnit_Inherit&&dimenX.GetUnit()!=eCSSUnit_Initial){ParseNonNegativeVariant(dimenY,VARIANT_LP|VARIANT_CALC,nullptr);}if(dimenX==dimenY||dimenY.GetUnit()==eCSSUnit_Null){AppendValue(aPropID,dimenX);}else{nsCSSValuevalue;value.SetPairValue(dimenX,dimenY);AppendValue(aPropID,value);}returntrue;}boolCSSParserImpl::ParseBoxCornerRadii(constnsCSSPropertyaPropIDs[]){// Rectangles are used as scratch storage.// top => top-left, right => top-right,// bottom => bottom-right, left => bottom-left.nsCSSRectdimenX,dimenY;int32_tcountX=0,countY=0;NS_FOR_CSS_SIDES(side){if(!ParseNonNegativeVariant(dimenX.*nsCSSRect::sides[side],(side>0?0:VARIANT_INHERIT)|VARIANT_LP|VARIANT_CALC,nullptr))break;countX++;}if(countX==0)returnfalse;if(ExpectSymbol('/',true)){NS_FOR_CSS_SIDES(side){if(!ParseNonNegativeVariant(dimenY.*nsCSSRect::sides[side],VARIANT_LP|VARIANT_CALC,nullptr))break;countY++;}if(countY==0)returnfalse;}if(!ExpectEndProperty())returnfalse;// if 'initial' or 'inherit' was used, it must be the only valueif(countX>1||countY>0){nsCSSUnitunit=dimenX.mTop.GetUnit();if(eCSSUnit_Inherit==unit||eCSSUnit_Initial==unit)returnfalse;}// if we have no Y-values, use the X-valuesif(countY==0){dimenY=dimenX;countY=countX;}// Provide missing values by replicating some of the values foundswitch(countX){case1:dimenX.mRight=dimenX.mTop;// top-right same as top-left, andcase2:dimenX.mBottom=dimenX.mTop;// bottom-right same as top-left, and case3:dimenX.mLeft=dimenX.mRight;// bottom-left same as top-right}switch(countY){case1:dimenY.mRight=dimenY.mTop;// top-right same as top-left, andcase2:dimenY.mBottom=dimenY.mTop;// bottom-right same as top-left, and case3:dimenY.mLeft=dimenY.mRight;// bottom-left same as top-right}NS_FOR_CSS_SIDES(side){nsCSSValue&x=dimenX.*nsCSSRect::sides[side];nsCSSValue&y=dimenY.*nsCSSRect::sides[side];if(x==y){AppendValue(aPropIDs[side],x);}else{nsCSSValuepair;pair.SetPairValue(x,y);AppendValue(aPropIDs[side],pair);}}returntrue;}// These must be in CSS order (top,right,bottom,left) for indexing to workstaticconstnsCSSPropertykBorderStyleIDs[]={eCSSProperty_border_top_style,eCSSProperty_border_right_style_value,eCSSProperty_border_bottom_style,eCSSProperty_border_left_style_value};staticconstnsCSSPropertykBorderWidthIDs[]={eCSSProperty_border_top_width,eCSSProperty_border_right_width_value,eCSSProperty_border_bottom_width,eCSSProperty_border_left_width_value};staticconstnsCSSPropertykBorderColorIDs[]={eCSSProperty_border_top_color,eCSSProperty_border_right_color_value,eCSSProperty_border_bottom_color,eCSSProperty_border_left_color_value};staticconstnsCSSPropertykBorderRadiusIDs[]={eCSSProperty_border_top_left_radius,eCSSProperty_border_top_right_radius,eCSSProperty_border_bottom_right_radius,eCSSProperty_border_bottom_left_radius};staticconstnsCSSPropertykOutlineRadiusIDs[]={eCSSProperty__moz_outline_radius_topLeft,eCSSProperty__moz_outline_radius_topRight,eCSSProperty__moz_outline_radius_bottomRight,eCSSProperty__moz_outline_radius_bottomLeft};boolCSSParserImpl::ParseProperty(nsCSSPropertyaPropID){// Can't use AutoRestore<bool> because it's a bitfield.NS_ABORT_IF_FALSE(!mHashlessColorQuirk,"hashless color quirk should not be set");NS_ABORT_IF_FALSE(!mUnitlessLengthQuirk,"unitless length quirk should not be set");if(mNavQuirkMode){mHashlessColorQuirk=nsCSSProps::PropHasFlags(aPropID,CSS_PROPERTY_HASHLESS_COLOR_QUIRK);mUnitlessLengthQuirk=nsCSSProps::PropHasFlags(aPropID,CSS_PROPERTY_UNITLESS_LENGTH_QUIRK);}NS_ASSERTION(aPropID<eCSSProperty_COUNT,"index out of range");boolresult;switch(nsCSSProps::PropertyParseType(aPropID)){caseCSS_PROPERTY_PARSE_INACCESSIBLE:{// The user can't use theseREPORT_UNEXPECTED(PEInaccessibleProperty2);result=false;break;}caseCSS_PROPERTY_PARSE_FUNCTION:{result=ParsePropertyByFunction(aPropID);break;}caseCSS_PROPERTY_PARSE_VALUE:{result=false;nsCSSValuevalue;if(ParseSingleValueProperty(value,aPropID)){if(ExpectEndProperty()){AppendValue(aPropID,value);result=true;}// XXX Report errors?}// XXX Report errors?break;}caseCSS_PROPERTY_PARSE_VALUE_LIST:{result=ParseValueList(aPropID);break;}default:{result=false;NS_ABORT_IF_FALSE(false,"Property's flags field in nsCSSPropList.h is missing ""one of the CSS_PROPERTY_PARSE_* constants");break;}}if(mNavQuirkMode){mHashlessColorQuirk=false;mUnitlessLengthQuirk=false;}returnresult;}boolCSSParserImpl::ParsePropertyByFunction(nsCSSPropertyaPropID){switch(aPropID){// handle shorthand or multiple propertiescaseeCSSProperty_background:returnParseBackground();caseeCSSProperty_background_repeat:returnParseBackgroundRepeat();caseeCSSProperty_background_position:returnParseBackgroundPosition();caseeCSSProperty_background_size:returnParseBackgroundSize();caseeCSSProperty_border:returnParseBorderSide(kBorderTopIDs,true);caseeCSSProperty_border_color:returnParseBorderColor();caseeCSSProperty_border_spacing:returnParseBorderSpacing();caseeCSSProperty_border_style:returnParseBorderStyle();caseeCSSProperty_border_bottom:returnParseBorderSide(kBorderBottomIDs,false);caseeCSSProperty_border_end:returnParseDirectionalBorderSide(kBorderEndIDs,NS_BOXPROP_SOURCE_LOGICAL);caseeCSSProperty_border_left:returnParseDirectionalBorderSide(kBorderLeftIDs,NS_BOXPROP_SOURCE_PHYSICAL);caseeCSSProperty_border_right:returnParseDirectionalBorderSide(kBorderRightIDs,NS_BOXPROP_SOURCE_PHYSICAL);caseeCSSProperty_border_start:returnParseDirectionalBorderSide(kBorderStartIDs,NS_BOXPROP_SOURCE_LOGICAL);caseeCSSProperty_border_top:returnParseBorderSide(kBorderTopIDs,false);caseeCSSProperty_border_bottom_colors:caseeCSSProperty_border_left_colors:caseeCSSProperty_border_right_colors:caseeCSSProperty_border_top_colors:returnParseBorderColors(aPropID);caseeCSSProperty_border_image_slice:returnParseBorderImageSlice(true,nullptr);caseeCSSProperty_border_image_width:returnParseBorderImageWidth(true);caseeCSSProperty_border_image_outset:returnParseBorderImageOutset(true);caseeCSSProperty_border_image_repeat:returnParseBorderImageRepeat(true);caseeCSSProperty_border_image:returnParseBorderImage();caseeCSSProperty_border_width:returnParseBorderWidth();caseeCSSProperty_border_end_color:returnParseDirectionalBoxProperty(eCSSProperty_border_end_color,NS_BOXPROP_SOURCE_LOGICAL);caseeCSSProperty_border_left_color:returnParseDirectionalBoxProperty(eCSSProperty_border_left_color,NS_BOXPROP_SOURCE_PHYSICAL);caseeCSSProperty_border_right_color:returnParseDirectionalBoxProperty(eCSSProperty_border_right_color,NS_BOXPROP_SOURCE_PHYSICAL);caseeCSSProperty_border_start_color:returnParseDirectionalBoxProperty(eCSSProperty_border_start_color,NS_BOXPROP_SOURCE_LOGICAL);caseeCSSProperty_border_end_width:returnParseDirectionalBoxProperty(eCSSProperty_border_end_width,NS_BOXPROP_SOURCE_LOGICAL);caseeCSSProperty_border_left_width:returnParseDirectionalBoxProperty(eCSSProperty_border_left_width,NS_BOXPROP_SOURCE_PHYSICAL);caseeCSSProperty_border_right_width:returnParseDirectionalBoxProperty(eCSSProperty_border_right_width,NS_BOXPROP_SOURCE_PHYSICAL);caseeCSSProperty_border_start_width:returnParseDirectionalBoxProperty(eCSSProperty_border_start_width,NS_BOXPROP_SOURCE_LOGICAL);caseeCSSProperty_border_end_style:returnParseDirectionalBoxProperty(eCSSProperty_border_end_style,NS_BOXPROP_SOURCE_LOGICAL);caseeCSSProperty_border_left_style:returnParseDirectionalBoxProperty(eCSSProperty_border_left_style,NS_BOXPROP_SOURCE_PHYSICAL);caseeCSSProperty_border_right_style:returnParseDirectionalBoxProperty(eCSSProperty_border_right_style,NS_BOXPROP_SOURCE_PHYSICAL);caseeCSSProperty_border_start_style:returnParseDirectionalBoxProperty(eCSSProperty_border_start_style,NS_BOXPROP_SOURCE_LOGICAL);caseeCSSProperty_border_radius:returnParseBoxCornerRadii(kBorderRadiusIDs);caseeCSSProperty__moz_outline_radius:returnParseBoxCornerRadii(kOutlineRadiusIDs);caseeCSSProperty_border_top_left_radius:caseeCSSProperty_border_top_right_radius:caseeCSSProperty_border_bottom_right_radius:caseeCSSProperty_border_bottom_left_radius:caseeCSSProperty__moz_outline_radius_topLeft:caseeCSSProperty__moz_outline_radius_topRight:caseeCSSProperty__moz_outline_radius_bottomRight:caseeCSSProperty__moz_outline_radius_bottomLeft:returnParseBoxCornerRadius(aPropID);caseeCSSProperty_box_shadow:caseeCSSProperty_text_shadow:returnParseShadowList(aPropID);caseeCSSProperty_clip:returnParseRect(eCSSProperty_clip);caseeCSSProperty__moz_columns:returnParseColumns();caseeCSSProperty__moz_column_rule:returnParseBorderSide(kColumnRuleIDs,false);caseeCSSProperty_content:returnParseContent();caseeCSSProperty_counter_increment:caseeCSSProperty_counter_reset:returnParseCounterData(aPropID);caseeCSSProperty_cursor:returnParseCursor();#ifdef MOZ_FLEXBOXcaseeCSSProperty_flex:returnParseFlex();#endif // MOZ_FLEXBOXcaseeCSSProperty_font:returnParseFont();caseeCSSProperty_image_region:returnParseRect(eCSSProperty_image_region);caseeCSSProperty_list_style:returnParseListStyle();caseeCSSProperty_margin:returnParseMargin();caseeCSSProperty_margin_end:returnParseDirectionalBoxProperty(eCSSProperty_margin_end,NS_BOXPROP_SOURCE_LOGICAL);caseeCSSProperty_margin_left:returnParseDirectionalBoxProperty(eCSSProperty_margin_left,NS_BOXPROP_SOURCE_PHYSICAL);caseeCSSProperty_margin_right:returnParseDirectionalBoxProperty(eCSSProperty_margin_right,NS_BOXPROP_SOURCE_PHYSICAL);caseeCSSProperty_margin_start:returnParseDirectionalBoxProperty(eCSSProperty_margin_start,NS_BOXPROP_SOURCE_LOGICAL);caseeCSSProperty_outline:returnParseOutline();caseeCSSProperty_overflow:returnParseOverflow();caseeCSSProperty_padding:returnParsePadding();caseeCSSProperty_padding_end:returnParseDirectionalBoxProperty(eCSSProperty_padding_end,NS_BOXPROP_SOURCE_LOGICAL);caseeCSSProperty_padding_left:returnParseDirectionalBoxProperty(eCSSProperty_padding_left,NS_BOXPROP_SOURCE_PHYSICAL);caseeCSSProperty_padding_right:returnParseDirectionalBoxProperty(eCSSProperty_padding_right,NS_BOXPROP_SOURCE_PHYSICAL);caseeCSSProperty_padding_start:returnParseDirectionalBoxProperty(eCSSProperty_padding_start,NS_BOXPROP_SOURCE_LOGICAL);caseeCSSProperty_quotes:returnParseQuotes();caseeCSSProperty_size:returnParseSize();caseeCSSProperty_text_decoration:returnParseTextDecoration();caseeCSSProperty_transform:returnParseTransform(false);caseeCSSProperty__moz_transform:returnParseTransform(true);caseeCSSProperty_transform_origin:returnParseTransformOrigin(false);caseeCSSProperty_perspective_origin:returnParseTransformOrigin(true);caseeCSSProperty_transition:returnParseTransition();caseeCSSProperty_animation:returnParseAnimation();caseeCSSProperty_transition_property:returnParseTransitionProperty();caseeCSSProperty_fill:caseeCSSProperty_stroke:returnParsePaint(aPropID);caseeCSSProperty_stroke_dasharray:returnParseDasharray();caseeCSSProperty_marker:returnParseMarker();caseeCSSProperty_paint_order:returnParsePaintOrder();default:NS_ABORT_IF_FALSE(false,"should not be called");returnfalse;}}// Bits used in determining which background position info we have#define BG_CENTER NS_STYLE_BG_POSITION_CENTER#define BG_TOP NS_STYLE_BG_POSITION_TOP#define BG_BOTTOM NS_STYLE_BG_POSITION_BOTTOM#define BG_LEFT NS_STYLE_BG_POSITION_LEFT#define BG_RIGHT NS_STYLE_BG_POSITION_RIGHT#define BG_CTB (BG_CENTER | BG_TOP | BG_BOTTOM)#define BG_TB (BG_TOP | BG_BOTTOM)#define BG_CLR (BG_CENTER | BG_LEFT | BG_RIGHT)#define BG_LR (BG_LEFT | BG_RIGHT)boolCSSParserImpl::ParseSingleValueProperty(nsCSSValue&aValue,nsCSSPropertyaPropID){if(aPropID==eCSSPropertyExtra_x_none_value){returnParseVariant(aValue,VARIANT_NONE|VARIANT_INHERIT,nullptr);}if(aPropID==eCSSPropertyExtra_x_auto_value){returnParseVariant(aValue,VARIANT_AUTO|VARIANT_INHERIT,nullptr);}if(aPropID<0||aPropID>=eCSSProperty_COUNT_no_shorthands){NS_ABORT_IF_FALSE(false,"not a single value property");returnfalse;}if(nsCSSProps::PropHasFlags(aPropID,CSS_PROPERTY_VALUE_PARSER_FUNCTION)){switch(aPropID){caseeCSSProperty_font_family:returnParseFamily(aValue);caseeCSSProperty_font_feature_settings:returnParseFontFeatureSettings(aValue);caseeCSSProperty_font_weight:returnParseFontWeight(aValue);caseeCSSProperty_marks:returnParseMarks(aValue);caseeCSSProperty_text_decoration_line:returnParseTextDecorationLine(aValue);caseeCSSProperty_text_overflow:returnParseTextOverflow(aValue);default:NS_ABORT_IF_FALSE(false,"should not reach here");returnfalse;}}uint32_tvariant=nsCSSProps::ParserVariant(aPropID);if(variant==0){NS_ABORT_IF_FALSE(false,"not a single value property");returnfalse;}// We only allow 'script-level' when unsafe rules are enabled, because// otherwise it could interfere with rulenode optimizations if used in// a non-MathML-enabled document.if(aPropID==eCSSProperty_script_level&&!mUnsafeRulesEnabled)returnfalse;constint32_t*kwtable=nsCSSProps::kKeywordTableTable[aPropID];switch(nsCSSProps::ValueRestrictions(aPropID)){default:NS_ABORT_IF_FALSE(false,"should not be reached");case0:returnParseVariant(aValue,variant,kwtable);caseCSS_PROPERTY_VALUE_NONNEGATIVE:returnParseNonNegativeVariant(aValue,variant,kwtable);caseCSS_PROPERTY_VALUE_AT_LEAST_ONE:returnParseOneOrLargerVariant(aValue,variant,kwtable);}}// nsFont::EnumerateFamilies callback for ParseFontDescriptorValuestructNS_STACK_CLASSExtractFirstFamilyData{nsAutoStringmFamilyName;boolmGood;ExtractFirstFamilyData():mFamilyName(),mGood(false){}};staticboolExtractFirstFamily(constnsString&aFamily,boolaGeneric,void*aData){ExtractFirstFamilyData*realData=(ExtractFirstFamilyData*)aData;if(aGeneric||realData->mFamilyName.Length()>0){realData->mGood=false;returnfalse;}realData->mFamilyName.Assign(aFamily);realData->mGood=true;returntrue;}// font-descriptor: descriptor ':' value ';'// caller has advanced mToken to point at the descriptorboolCSSParserImpl::ParseFontDescriptorValue(nsCSSFontDescaDescID,nsCSSValue&aValue){switch(aDescID){// These four are similar to the properties of the same name,// possibly with more restrictions on the values they can take.caseeCSSFontDesc_Family:{if(!ParseFamily(aValue)||aValue.GetUnit()!=eCSSUnit_Families)returnfalse;// the style parameters to the nsFont constructor are ignored,// because it's only being used to call EnumerateFamiliesnsAutoStringvalueStr;aValue.GetStringValue(valueStr);nsFontfont(valueStr,0,0,0,0,0,0);ExtractFirstFamilyDatadat;font.EnumerateFamilies(ExtractFirstFamily,(void*)&dat);if(!dat.mGood)returnfalse;aValue.SetStringValue(dat.mFamilyName,eCSSUnit_String);returntrue;}caseeCSSFontDesc_Style:// property is VARIANT_HMK|VARIANT_SYSFONTreturnParseVariant(aValue,VARIANT_KEYWORD|VARIANT_NORMAL,nsCSSProps::kFontStyleKTable);caseeCSSFontDesc_Weight:return(ParseFontWeight(aValue)&&aValue.GetUnit()!=eCSSUnit_Inherit&&aValue.GetUnit()!=eCSSUnit_Initial&&(aValue.GetUnit()!=eCSSUnit_Enumerated||(aValue.GetIntValue()!=NS_STYLE_FONT_WEIGHT_BOLDER&&aValue.GetIntValue()!=NS_STYLE_FONT_WEIGHT_LIGHTER)));caseeCSSFontDesc_Stretch:// property is VARIANT_HK|VARIANT_SYSFONTreturnParseVariant(aValue,VARIANT_KEYWORD,nsCSSProps::kFontStretchKTable);// These two are unique to @font-face and have their own special grammar.caseeCSSFontDesc_Src:returnParseFontSrc(aValue);caseeCSSFontDesc_UnicodeRange:returnParseFontRanges(aValue);caseeCSSFontDesc_FontFeatureSettings:returnParseFontFeatureSettings(aValue);caseeCSSFontDesc_FontLanguageOverride:returnParseVariant(aValue,VARIANT_NORMAL|VARIANT_STRING,nullptr);caseeCSSFontDesc_UNKNOWN:caseeCSSFontDesc_COUNT:NS_NOTREACHED("bad nsCSSFontDesc code");}// explicitly do NOT have a default case to let the compiler// help find missing descriptorsreturnfalse;}voidCSSParserImpl::InitBoxPropsAsPhysical(constnsCSSProperty*aSourceProperties){nsCSSValuephysical(NS_BOXPROP_SOURCE_PHYSICAL,eCSSUnit_Enumerated);for(constnsCSSProperty*prop=aSourceProperties;*prop!=eCSSProperty_UNKNOWN;++prop){AppendValue(*prop,physical);}}staticnsCSSValueBoxPositionMaskToCSSValue(int32_taMask,boolisX){int32_tval=NS_STYLE_BG_POSITION_CENTER;if(isX){if(aMask&BG_LEFT){val=NS_STYLE_BG_POSITION_LEFT;}elseif(aMask&BG_RIGHT){val=NS_STYLE_BG_POSITION_RIGHT;}}else{if(aMask&BG_TOP){val=NS_STYLE_BG_POSITION_TOP;}elseif(aMask&BG_BOTTOM){val=NS_STYLE_BG_POSITION_BOTTOM;}}returnnsCSSValue(val,eCSSUnit_Enumerated);}boolCSSParserImpl::ParseBackground(){nsAutoParseCompoundPropertycompound(this);// background-color can only be set once, so it's not a list.nsCSSValuecolor;// Check first for inherit/initial.if(ParseVariant(color,VARIANT_INHERIT,nullptr)){// must be aloneif(!ExpectEndProperty()){returnfalse;}for(constnsCSSProperty*subprops=nsCSSProps::SubpropertyEntryFor(eCSSProperty_background);*subprops!=eCSSProperty_UNKNOWN;++subprops){AppendValue(*subprops,color);}returntrue;}nsCSSValueimage,repeat,attachment,clip,origin,position,size;BackgroundParseStatestate(color,image.SetListValue(),repeat.SetPairListValue(),attachment.SetListValue(),clip.SetListValue(),origin.SetListValue(),position.SetListValue(),size.SetPairListValue());for(;;){if(!ParseBackgroundItem(state)){returnfalse;}if(CheckEndProperty()){break;}// If we saw a color, this must be the last item.if(color.GetUnit()!=eCSSUnit_Null){REPORT_UNEXPECTED_TOKEN(PEExpectEndValue);returnfalse;}// Otherwise, a comma is mandatory.if(!ExpectSymbol(',',true)){returnfalse;}// Chain another entry on all the lists.state.mImage->mNext=newnsCSSValueList;state.mImage=state.mImage->mNext;state.mRepeat->mNext=newnsCSSValuePairList;state.mRepeat=state.mRepeat->mNext;state.mAttachment->mNext=newnsCSSValueList;state.mAttachment=state.mAttachment->mNext;state.mClip->mNext=newnsCSSValueList;state.mClip=state.mClip->mNext;state.mOrigin->mNext=newnsCSSValueList;state.mOrigin=state.mOrigin->mNext;state.mPosition->mNext=newnsCSSValueList;state.mPosition=state.mPosition->mNext;state.mSize->mNext=newnsCSSValuePairList;state.mSize=state.mSize->mNext;}// If we get to this point without seeing a color, provide a default.if(color.GetUnit()==eCSSUnit_Null){color.SetColorValue(NS_RGBA(0,0,0,0));}AppendValue(eCSSProperty_background_image,image);AppendValue(eCSSProperty_background_repeat,repeat);AppendValue(eCSSProperty_background_attachment,attachment);AppendValue(eCSSProperty_background_clip,clip);AppendValue(eCSSProperty_background_origin,origin);AppendValue(eCSSProperty_background_position,position);AppendValue(eCSSProperty_background_size,size);AppendValue(eCSSProperty_background_color,color);returntrue;}// Parse one item of the background shorthand property.boolCSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundParseState&aState){// Fill in the values that the shorthand will set if we don't find// other values.aState.mImage->mValue.SetNoneValue();aState.mRepeat->mXValue.SetIntValue(NS_STYLE_BG_REPEAT_REPEAT,eCSSUnit_Enumerated);aState.mRepeat->mYValue.Reset();aState.mAttachment->mValue.SetIntValue(NS_STYLE_BG_ATTACHMENT_SCROLL,eCSSUnit_Enumerated);aState.mClip->mValue.SetIntValue(NS_STYLE_BG_CLIP_BORDER,eCSSUnit_Enumerated);aState.mOrigin->mValue.SetIntValue(NS_STYLE_BG_ORIGIN_PADDING,eCSSUnit_Enumerated);nsRefPtr<nsCSSValue::Array>positionArr=nsCSSValue::Array::Create(4);aState.mPosition->mValue.SetArrayValue(positionArr,eCSSUnit_Array);positionArr->Item(1).SetPercentValue(0.0f);positionArr->Item(3).SetPercentValue(0.0f);aState.mSize->mXValue.SetAutoValue();aState.mSize->mYValue.SetAutoValue();boolhaveColor=false,haveImage=false,haveRepeat=false,haveAttach=false,havePositionAndSize=false,haveOrigin=false,haveSomething=false;while(GetToken(true)){nsCSSTokenTypett=mToken.mType;UngetToken();// ...but we'll still cheat and use mTokenif(tt==eCSSToken_Symbol){// ExpectEndProperty only looks for symbols, and nothing else will// show up as one.break;}if(tt==eCSSToken_Ident){nsCSSKeywordkeyword=nsCSSKeywords::LookupKeyword(mToken.mIdent);int32_tdummy;if(keyword==eCSSKeyword_inherit||keyword==eCSSKeyword__moz_initial||keyword==eCSSKeyword_initial){returnfalse;}elseif(keyword==eCSSKeyword_none){if(haveImage)returnfalse;haveImage=true;if(!ParseSingleValueProperty(aState.mImage->mValue,eCSSProperty_background_image)){NS_NOTREACHED("should be able to parse");returnfalse;}}elseif(nsCSSProps::FindKeyword(keyword,nsCSSProps::kBackgroundAttachmentKTable,dummy)){if(haveAttach)returnfalse;haveAttach=true;if(!ParseSingleValueProperty(aState.mAttachment->mValue,eCSSProperty_background_attachment)){NS_NOTREACHED("should be able to parse");returnfalse;}}elseif(nsCSSProps::FindKeyword(keyword,nsCSSProps::kBackgroundRepeatKTable,dummy)){if(haveRepeat)returnfalse;haveRepeat=true;nsCSSValuePairscratch;if(!ParseBackgroundRepeatValues(scratch)){NS_NOTREACHED("should be able to parse");returnfalse;}aState.mRepeat->mXValue=scratch.mXValue;aState.mRepeat->mYValue=scratch.mYValue;}elseif(nsCSSProps::FindKeyword(keyword,nsCSSProps::kBackgroundPositionKTable,dummy)){if(havePositionAndSize)returnfalse;havePositionAndSize=true;if(!ParseBackgroundPositionValues(aState.mPosition->mValue,false)){returnfalse;}if(ExpectSymbol('/',true)){nsCSSValuePairscratch;if(!ParseBackgroundSizeValues(scratch)){returnfalse;}aState.mSize->mXValue=scratch.mXValue;aState.mSize->mYValue=scratch.mYValue;}}elseif(nsCSSProps::FindKeyword(keyword,nsCSSProps::kBackgroundOriginKTable,dummy)){if(haveOrigin)returnfalse;haveOrigin=true;if(!ParseSingleValueProperty(aState.mOrigin->mValue,eCSSProperty_background_origin)){NS_NOTREACHED("should be able to parse");returnfalse;}MOZ_STATIC_ASSERT(NS_STYLE_BG_CLIP_BORDER==NS_STYLE_BG_ORIGIN_BORDER&&NS_STYLE_BG_CLIP_PADDING==NS_STYLE_BG_ORIGIN_PADDING&&NS_STYLE_BG_CLIP_CONTENT==NS_STYLE_BG_ORIGIN_CONTENT,"bg-clip and bg-origin style constants must agree");aState.mClip->mValue=aState.mOrigin->mValue;}else{if(haveColor)returnfalse;haveColor=true;if(!ParseSingleValueProperty(aState.mColor,eCSSProperty_background_color)){returnfalse;}}}elseif(tt==eCSSToken_URL||(tt==eCSSToken_Function&&(mToken.mIdent.LowerCaseEqualsLiteral("linear-gradient")||mToken.mIdent.LowerCaseEqualsLiteral("radial-gradient")||mToken.mIdent.LowerCaseEqualsLiteral("repeating-linear-gradient")||mToken.mIdent.LowerCaseEqualsLiteral("repeating-radial-gradient")||mToken.mIdent.LowerCaseEqualsLiteral("-moz-linear-gradient")||mToken.mIdent.LowerCaseEqualsLiteral("-moz-radial-gradient")||mToken.mIdent.LowerCaseEqualsLiteral("-moz-repeating-linear-gradient")||mToken.mIdent.LowerCaseEqualsLiteral("-moz-repeating-radial-gradient")||mToken.mIdent.LowerCaseEqualsLiteral("-moz-image-rect")||mToken.mIdent.LowerCaseEqualsLiteral("-moz-element")))){if(haveImage)returnfalse;haveImage=true;if(!ParseSingleValueProperty(aState.mImage->mValue,eCSSProperty_background_image)){returnfalse;}}elseif(tt==eCSSToken_Dimension||tt==eCSSToken_Number||tt==eCSSToken_Percentage||(tt==eCSSToken_Function&&(mToken.mIdent.LowerCaseEqualsLiteral("calc")||mToken.mIdent.LowerCaseEqualsLiteral("-moz-calc")))){if(havePositionAndSize)returnfalse;havePositionAndSize=true;if(!ParseBackgroundPositionValues(aState.mPosition->mValue,false)){returnfalse;}if(ExpectSymbol('/',true)){nsCSSValuePairscratch;if(!ParseBackgroundSizeValues(scratch)){returnfalse;}aState.mSize->mXValue=scratch.mXValue;aState.mSize->mYValue=scratch.mYValue;}}else{if(haveColor)returnfalse;haveColor=true;// Note: This parses 'inherit' and 'initial', but// we've already checked for them, so it's ok.if(!ParseSingleValueProperty(aState.mColor,eCSSProperty_background_color)){returnfalse;}}haveSomething=true;}returnhaveSomething;}// This function is very similar to ParseBackgroundPosition and// ParseBackgroundSize.boolCSSParserImpl::ParseValueList(nsCSSPropertyaPropID){// aPropID is a single value prop-idnsCSSValuevalue;if(ParseVariant(value,VARIANT_INHERIT,nullptr)){// 'initial' and 'inherit' stand alone, no list permitted.if(!ExpectEndProperty()){returnfalse;}}else{nsCSSValueList*item=value.SetListValue();for(;;){if(!ParseSingleValueProperty(item->mValue,aPropID)){returnfalse;}if(CheckEndProperty()){break;}if(!ExpectSymbol(',',true)){returnfalse;}item->mNext=newnsCSSValueList;item=item->mNext;}}AppendValue(aPropID,value);returntrue;}boolCSSParserImpl::ParseBackgroundRepeat(){nsCSSValuevalue;if(ParseVariant(value,VARIANT_INHERIT,nullptr)){// 'initial' and 'inherit' stand alone, no list permitted.if(!ExpectEndProperty()){returnfalse;}}else{nsCSSValuePairvaluePair;if(!ParseBackgroundRepeatValues(valuePair)){returnfalse;}nsCSSValuePairList*item=value.SetPairListValue();for(;;){item->mXValue=valuePair.mXValue;item->mYValue=valuePair.mYValue;if(CheckEndProperty()){break;}if(!ExpectSymbol(',',true)){returnfalse;}if(!ParseBackgroundRepeatValues(valuePair)){returnfalse;}item->mNext=newnsCSSValuePairList;item=item->mNext;}}AppendValue(eCSSProperty_background_repeat,value);returntrue;}boolCSSParserImpl::ParseBackgroundRepeatValues(nsCSSValuePair&aValue){nsCSSValue&xValue=aValue.mXValue;nsCSSValue&yValue=aValue.mYValue;if(ParseEnum(xValue,nsCSSProps::kBackgroundRepeatKTable)){int32_tvalue=xValue.GetIntValue();// For single values set yValue as eCSSUnit_Null.if(value==NS_STYLE_BG_REPEAT_REPEAT_X||value==NS_STYLE_BG_REPEAT_REPEAT_Y||!ParseEnum(yValue,nsCSSProps::kBackgroundRepeatPartKTable)){// the caller will fail cases like "repeat-x no-repeat"// by expecting a list separator or an end property.yValue.Reset();}returntrue;}returnfalse;}// This function is very similar to ParseBackgroundList and ParseBackgroundSize.boolCSSParserImpl::ParseBackgroundPosition(){nsCSSValuevalue;if(ParseVariant(value,VARIANT_INHERIT,nullptr)){// 'initial' and 'inherit' stand alone, no list permitted.if(!ExpectEndProperty()){returnfalse;}}else{nsCSSValueitemValue;if(!ParseBackgroundPositionValues(itemValue,false)){returnfalse;}nsCSSValueList*item=value.SetListValue();for(;;){item->mValue=itemValue;if(CheckEndProperty()){break;}if(!ExpectSymbol(',',true)){returnfalse;}if(!ParseBackgroundPositionValues(itemValue,false)){returnfalse;}item->mNext=newnsCSSValueList;item=item->mNext;}}AppendValue(eCSSProperty_background_position,value);returntrue;}/** * BoxPositionMaskToCSSValue and ParseBoxPositionValues are used * for parsing the CSS 2.1 background-position syntax (which has at * most two values). (Compare to the css3-background syntax which * takes up to four values.) Some current CSS specifications that * use background-position-like syntax still use this old syntax. ** * Parses two values that correspond to positions in a box. These can be * values corresponding to percentages of the box, raw offsets, or keywords * like "top," "left center," etc. * * @param aOut The nsCSSValuePair in which to place the result. * @param aAcceptsInherit If true, 'inherit' and 'initial' are legal values * @param aAllowExplicitCenter If true, 'center' is a legal value * @return Whether or not the operation succeeded. */boolCSSParserImpl::ParseBoxPositionValues(nsCSSValuePair&aOut,boolaAcceptsInherit,boolaAllowExplicitCenter){// First try a percentage or a length valuensCSSValue&xValue=aOut.mXValue,&yValue=aOut.mYValue;int32_tvariantMask=(aAcceptsInherit?VARIANT_INHERIT:0)|VARIANT_LP|VARIANT_CALC;if(ParseVariant(xValue,variantMask,nullptr)){if(eCSSUnit_Inherit==xValue.GetUnit()||eCSSUnit_Initial==xValue.GetUnit()){// both are inherited or both are set to initialyValue=xValue;returntrue;}// We have one percentage/length/calc. Get the optional second// percentage/length/calc/keyword.if(ParseVariant(yValue,VARIANT_LP|VARIANT_CALC,nullptr)){// We have two numbersreturntrue;}if(ParseEnum(yValue,nsCSSProps::kBackgroundPositionKTable)){int32_tyVal=yValue.GetIntValue();if(!(yVal&BG_CTB)){// The second keyword can only be 'center', 'top', or 'bottom'returnfalse;}yValue=BoxPositionMaskToCSSValue(yVal,false);returntrue;}// If only one percentage or length value is given, it sets the// horizontal position only, and the vertical position will be 50%.yValue.SetPercentValue(0.5f);returntrue;}// Now try keywords. We do this manually to allow for the first// appearance of "center" to apply to the either the x or y// position (it's ambiguous so we have to disambiguate). Each// allowed keyword value is assigned it's own bit. We don't allow// any duplicate keywords other than center. We try to get two// keywords but it's okay if there is only one.int32_tmask=0;if(ParseEnum(xValue,nsCSSProps::kBackgroundPositionKTable)){int32_tbit=xValue.GetIntValue();mask|=bit;if(ParseEnum(xValue,nsCSSProps::kBackgroundPositionKTable)){bit=xValue.GetIntValue();if(mask&(bit&~BG_CENTER)){// Only the 'center' keyword can be duplicated.returnfalse;}mask|=bit;}else{// Only one keyword. See if we have a length, percentage, or calc.if(ParseVariant(yValue,VARIANT_LP|VARIANT_CALC,nullptr)){if(!(mask&BG_CLR)){// The first keyword can only be 'center', 'left', or 'right'returnfalse;}xValue=BoxPositionMaskToCSSValue(mask,true);returntrue;}}}// Check for bad input. Bad input consists of no matching keywords,// or pairs of x keywords or pairs of y keywords.if((mask==0)||(mask==(BG_TOP|BG_BOTTOM))||(mask==(BG_LEFT|BG_RIGHT))||(!aAllowExplicitCenter&&(mask&BG_CENTER))){returnfalse;}// Create style valuesxValue=BoxPositionMaskToCSSValue(mask,true);yValue=BoxPositionMaskToCSSValue(mask,false);returntrue;}boolCSSParserImpl::ParseBackgroundPositionValues(nsCSSValue&aOut,boolaAcceptsInherit){// css3-background allows positions to be defined as offsets// from an edge. There can be 2 keywords and 2 offsets given. These// four 'values' are stored in an array in the following order:// [keyword offset keyword offset]. If a keyword or offset isn't// parsed the value of the corresponding array element is set// to eCSSUnit_Null by a call to nsCSSValue::Reset().if(aAcceptsInherit&&ParseVariant(aOut,VARIANT_INHERIT,nullptr)){returntrue;}nsRefPtr<nsCSSValue::Array>value=nsCSSValue::Array::Create(4);aOut.SetArrayValue(value,eCSSUnit_Array);// The following clarifies organisation of the array.nsCSSValue&xEdge=value->Item(0),&xOffset=value->Item(1),&yEdge=value->Item(2),&yOffset=value->Item(3);// Parse all the values into the array.uint32_tvalueCount=0;for(int32_ti=0;i<4;i++){if(!ParseVariant(value->Item(i),VARIANT_LPCALC|VARIANT_KEYWORD,nsCSSProps::kBackgroundPositionKTable)){break;}++valueCount;}switch(valueCount){case4:// "If three or four values are given, then each <percentage> or <length>// represents an offset and must be preceded by a keyword, which specifies// from which edge the offset is given."if(eCSSUnit_Enumerated!=xEdge.GetUnit()||BG_CENTER==xEdge.GetIntValue()||eCSSUnit_Enumerated==xOffset.GetUnit()||eCSSUnit_Enumerated!=yEdge.GetUnit()||BG_CENTER==yEdge.GetIntValue()||eCSSUnit_Enumerated==yOffset.GetUnit()){returnfalse;}break;case3:// "If three or four values are given, then each <percentage> or<length>// represents an offset and must be preceded by a keyword, which specifies// from which edge the offset is given." ... "If three values are given,// the missing offset is assumed to be zero."if(eCSSUnit_Enumerated!=value->Item(1).GetUnit()){// keyword offset keyword// Second value is non-keyword, thus first value must be a non-center// keyword.if(eCSSUnit_Enumerated!=value->Item(0).GetUnit()||BG_CENTER==value->Item(0).GetIntValue()){returnfalse;}// Remaining value must be a keyword.if(eCSSUnit_Enumerated!=value->Item(2).GetUnit()){returnfalse;}yOffset.Reset();// Everything else is in the correct position.}elseif(eCSSUnit_Enumerated!=value->Item(2).GetUnit()){// keyword keyword offset// Third value is non-keyword, thus second value must be non-center// keyword.if(BG_CENTER==value->Item(1).GetIntValue()){returnfalse;}// Remaining value must be a keyword.if(eCSSUnit_Enumerated!=value->Item(0).GetUnit()){returnfalse;}// Move the values to the correct position in the array.value->Item(3)=value->Item(2);// yOffsetvalue->Item(2)=value->Item(1);// yEdgevalue->Item(1).Reset();// xOffset}else{returnfalse;}break;case2:// "If two values are given and at least one value is not a keyword, then// the first value represents the horizontal position (or offset) and the// second represents the vertical position (or offset)"if(eCSSUnit_Enumerated==value->Item(0).GetUnit()){if(eCSSUnit_Enumerated==value->Item(1).GetUnit()){// keyword keywordvalue->Item(2)=value->Item(1);// move yEdge to correct positionxOffset.Reset();yOffset.Reset();}else{// keyword offset// First value must represent horizontal position.if((BG_TOP|BG_BOTTOM)&value->Item(0).GetIntValue()){returnfalse;}value->Item(3)=value->Item(1);// move yOffset to correct positionxOffset.Reset();yEdge.Reset();}}else{if(eCSSUnit_Enumerated==value->Item(1).GetUnit()){// offset keyword// Second value must represent vertical position.if((BG_LEFT|BG_RIGHT)&value->Item(1).GetIntValue()){returnfalse;}value->Item(2)=value->Item(1);// move yEdge to correct positionvalue->Item(1)=value->Item(0);// move xOffset to correct positionxEdge.Reset();yOffset.Reset();}else{// offset offsetvalue->Item(3)=value->Item(1);// move yOffset to correct positionvalue->Item(1)=value->Item(0);// move xOffset to correct positionxEdge.Reset();yEdge.Reset();}}break;case1:// "If only one value is specified, the second value is assumed to be// center."if(eCSSUnit_Enumerated==value->Item(0).GetUnit()){xOffset.Reset();}else{value->Item(1)=value->Item(0);// move xOffset to correct positionxEdge.Reset();}yEdge.SetIntValue(NS_STYLE_BG_POSITION_CENTER,eCSSUnit_Enumerated);yOffset.Reset();break;default:returnfalse;}// For compatibility with CSS2.1 code the edges can be unspecified.// Unspecified edges are recorded as NULL.NS_ASSERTION((eCSSUnit_Enumerated==xEdge.GetUnit()||eCSSUnit_Null==xEdge.GetUnit())&&(eCSSUnit_Enumerated==yEdge.GetUnit()||eCSSUnit_Null==yEdge.GetUnit())&&eCSSUnit_Enumerated!=xOffset.GetUnit()&&eCSSUnit_Enumerated!=yOffset.GetUnit(),"Unexpected units");// Keywords in first and second pairs can not both be vertical or// horizontal keywords. (eg. left right, bottom top). Additionally,// non-center keyword can not be duplicated (eg. left left).int32_txEdgeEnum=xEdge.GetUnit()==eCSSUnit_Enumerated?xEdge.GetIntValue():0;int32_tyEdgeEnum=yEdge.GetUnit()==eCSSUnit_Enumerated?yEdge.GetIntValue():0;if((xEdgeEnum|yEdgeEnum)==(BG_LEFT|BG_RIGHT)||(xEdgeEnum|yEdgeEnum)==(BG_TOP|BG_BOTTOM)||(xEdgeEnum&yEdgeEnum&~BG_CENTER)){returnfalse;}// The values could be in an order that is different than expected.// eg. x contains vertical information, y contains horizontal information.// Swap if incorrect order.if(xEdgeEnum&(BG_TOP|BG_BOTTOM)||yEdgeEnum&(BG_LEFT|BG_RIGHT)){nsCSSValueswapEdge=xEdge;nsCSSValueswapOffset=xOffset;xEdge=yEdge;xOffset=yOffset;yEdge=swapEdge;yOffset=swapOffset;}returntrue;}// This function is very similar to ParseBackgroundList and// ParseBackgroundPosition.boolCSSParserImpl::ParseBackgroundSize(){nsCSSValuevalue;if(ParseVariant(value,VARIANT_INHERIT,nullptr)){// 'initial' and 'inherit' stand alone, no list permitted.if(!ExpectEndProperty()){returnfalse;}}else{nsCSSValuePairvaluePair;if(!ParseBackgroundSizeValues(valuePair)){returnfalse;}nsCSSValuePairList*item=value.SetPairListValue();for(;;){item->mXValue=valuePair.mXValue;item->mYValue=valuePair.mYValue;if(CheckEndProperty()){break;}if(!ExpectSymbol(',',true)){returnfalse;}if(!ParseBackgroundSizeValues(valuePair)){returnfalse;}item->mNext=newnsCSSValuePairList;item=item->mNext;}}AppendValue(eCSSProperty_background_size,value);returntrue;}/** * Parses two values that correspond to lengths for the background-size * property. These can be one or two lengths (or the 'auto' keyword) or * percentages corresponding to the element's dimensions or the single keywords * 'contain' or 'cover'. 'initial' and 'inherit' must be handled by the caller * if desired. * * @param aOut The nsCSSValuePair in which to place the result. * @return Whether or not the operation succeeded. */#define BG_SIZE_VARIANT (VARIANT_LP | VARIANT_AUTO | VARIANT_CALC)boolCSSParserImpl::ParseBackgroundSizeValues(nsCSSValuePair&aOut){// First try a percentage or a length valuensCSSValue&xValue=aOut.mXValue,&yValue=aOut.mYValue;if(ParseNonNegativeVariant(xValue,BG_SIZE_VARIANT,nullptr)){// We have one percentage/length/calc/auto. Get the optional second// percentage/length/calc/keyword.if(ParseNonNegativeVariant(yValue,BG_SIZE_VARIANT,nullptr)){// We have a second percentage/length/calc/auto.returntrue;}// If only one percentage or length value is given, it sets the// horizontal size only, and the vertical size will be as if by 'auto'.yValue.SetAutoValue();returntrue;}// Now address 'contain' and 'cover'.if(!ParseEnum(xValue,nsCSSProps::kBackgroundSizeKTable))returnfalse;yValue.Reset();returntrue;}#undef BG_SIZE_VARIANTboolCSSParserImpl::ParseBorderColor(){staticconstnsCSSPropertykBorderColorSources[]={eCSSProperty_border_left_color_ltr_source,eCSSProperty_border_left_color_rtl_source,eCSSProperty_border_right_color_ltr_source,eCSSProperty_border_right_color_rtl_source,eCSSProperty_UNKNOWN};// do this now, in case 4 values weren't specifiedInitBoxPropsAsPhysical(kBorderColorSources);returnParseBoxProperties(kBorderColorIDs);}voidCSSParserImpl::SetBorderImageInitialValues(){// border-image-source: nonensCSSValuesource;source.SetNoneValue();AppendValue(eCSSProperty_border_image_source,source);// border-image-slice: 100%nsCSSValuesliceBoxValue;nsCSSRect&sliceBox=sliceBoxValue.SetRectValue();sliceBox.SetAllSidesTo(nsCSSValue(1.0f,eCSSUnit_Percent));nsCSSValueslice;nsCSSValueList*sliceList=slice.SetListValue();sliceList->mValue=sliceBoxValue;AppendValue(eCSSProperty_border_image_slice,slice);// border-image-width: 1nsCSSValuewidth;nsCSSRect&widthBox=width.SetRectValue();widthBox.SetAllSidesTo(nsCSSValue(1.0f,eCSSUnit_Number));AppendValue(eCSSProperty_border_image_width,width);// border-image-outset: 0nsCSSValueoutset;nsCSSRect&outsetBox=outset.SetRectValue();outsetBox.SetAllSidesTo(nsCSSValue(0.0f,eCSSUnit_Number));AppendValue(eCSSProperty_border_image_outset,outset);// border-image-repeat: repeatnsCSSValuerepeat;nsCSSValuePairrepeatPair;repeatPair.SetBothValuesTo(nsCSSValue(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH,eCSSUnit_Enumerated));repeat.SetPairValue(&repeatPair);AppendValue(eCSSProperty_border_image_repeat,repeat);}boolCSSParserImpl::ParseBorderImageSlice(boolaAcceptsInherit,bool*aConsumedTokens){// border-image-slice: initial | [<number>|<percentage>]{1,4} && fill?nsCSSValuevalue;if(aConsumedTokens){*aConsumedTokens=true;}if(aAcceptsInherit&&ParseVariant(value,VARIANT_INHERIT,nullptr)){// Keyword "inherit" can not be mixed, so we are done.AppendValue(eCSSProperty_border_image_slice,value);returntrue;}// Try parsing "fill" value.nsCSSValueimageSliceFillValue;boolhasFill=ParseEnum(imageSliceFillValue,nsCSSProps::kBorderImageSliceKTable);// Parse the box dimensions.nsCSSValueimageSliceBoxValue;if(!ParseGroupedBoxProperty(VARIANT_PN,imageSliceBoxValue)){if(!hasFill&&aConsumedTokens){*aConsumedTokens=false;}returnfalse;}// Try parsing "fill" keyword again if the first time failed because keyword// and slice dimensions can be in any order.if(!hasFill){hasFill=ParseEnum(imageSliceFillValue,nsCSSProps::kBorderImageSliceKTable);}nsCSSValueList*borderImageSlice=value.SetListValue();// Put the box value into the list.borderImageSlice->mValue=imageSliceBoxValue;if(hasFill){// Put the "fill" value into the list.borderImageSlice->mNext=newnsCSSValueList;borderImageSlice->mNext->mValue=imageSliceFillValue;}AppendValue(eCSSProperty_border_image_slice,value);returntrue;}boolCSSParserImpl::ParseBorderImageWidth(boolaAcceptsInherit){// border-image-width: initial | [<length>|<number>|<percentage>|auto]{1,4}nsCSSValuevalue;if(aAcceptsInherit&&ParseVariant(value,VARIANT_INHERIT,nullptr)){// Keyword "inherit" can no be mixed, so we are done.AppendValue(eCSSProperty_border_image_width,value);returntrue;}// Parse the box dimensions.if(!ParseGroupedBoxProperty(VARIANT_ALPN,value)){returnfalse;}AppendValue(eCSSProperty_border_image_width,value);returntrue;}boolCSSParserImpl::ParseBorderImageOutset(boolaAcceptsInherit){// border-image-outset: initial | [<length>|<number>]{1,4}nsCSSValuevalue;if(aAcceptsInherit&&ParseVariant(value,VARIANT_INHERIT,nullptr)){// Keyword "inherit" can not be mixed, so we are done.AppendValue(eCSSProperty_border_image_outset,value);returntrue;}// Parse the box dimensions.if(!ParseGroupedBoxProperty(VARIANT_LN,value)){returnfalse;}AppendValue(eCSSProperty_border_image_outset,value);returntrue;}boolCSSParserImpl::ParseBorderImageRepeat(boolaAcceptsInherit){nsCSSValuevalue;if(aAcceptsInherit&&ParseVariant(value,VARIANT_INHERIT,nullptr)){// Keyword "inherit" can not be mixed, so we are done.AppendValue(eCSSProperty_border_image_repeat,value);returntrue;}nsCSSValuePairresult;if(!ParseEnum(result.mXValue,nsCSSProps::kBorderImageRepeatKTable)){returnfalse;}// optional second keyword, defaults to firstif(!ParseEnum(result.mYValue,nsCSSProps::kBorderImageRepeatKTable)){result.mYValue=result.mXValue;}value.SetPairValue(&result);AppendValue(eCSSProperty_border_image_repeat,value);returntrue;}boolCSSParserImpl::ParseBorderImage(){nsAutoParseCompoundPropertycompound(this);// border-image: inherit | initial |// <border-image-source> ||// <border-image-slice>// [ / <border-image-width> |// / <border-image-width>? / <border-image-outset> ]? ||// <border-image-repeat>nsCSSValuevalue;if(ParseVariant(value,VARIANT_INHERIT,nullptr)){AppendValue(eCSSProperty_border_image_source,value);AppendValue(eCSSProperty_border_image_slice,value);AppendValue(eCSSProperty_border_image_width,value);AppendValue(eCSSProperty_border_image_outset,value);AppendValue(eCSSProperty_border_image_repeat,value);// Keyword "inherit" (and "initial") can't be mixed, so we are done.returntrue;}// No empty property.if(CheckEndProperty()){returnfalse;}// Shorthand properties are required to set everything they can.SetBorderImageInitialValues();boolfoundSource=false;boolfoundSliceWidthOutset=false;boolfoundRepeat=false;// This loop is used to handle the parsing of border-image properties which// can appear in any order.nsCSSValueimageSourceValue;while(!CheckEndProperty()){// <border-image-source>if(!foundSource&&ParseVariant(imageSourceValue,VARIANT_UO,nullptr)){AppendValue(eCSSProperty_border_image_source,imageSourceValue);foundSource=true;continue;}// <border-image-slice>// ParseBorderImageSlice is weird. It may consume tokens and then return// false, because it parses a property with two required components that// can appear in either order. Since the tokens that were consumed cannot// parse as anything else we care about, this isn't a problem.if(!foundSliceWidthOutset){boolsliceConsumedTokens=false;if(ParseBorderImageSlice(false,&sliceConsumedTokens)){foundSliceWidthOutset=true;// [ / <border-image-width>?if(ExpectSymbol('/',true)){boolfoundBorderImageWidth=ParseBorderImageWidth(false);// [ / <border-image-outset>if(ExpectSymbol('/',true)){if(!ParseBorderImageOutset(false)){returnfalse;}}elseif(!foundBorderImageWidth){// If this part has an trailing slash, the whole declaration is // invalid.returnfalse;}}continue;}else{// If we consumed some tokens for <border-image-slice> but did not// successfully parse it, we have an error.if(sliceConsumedTokens){returnfalse;}}}// <border-image-repeat>if(!foundRepeat&&ParseBorderImageRepeat(false)){foundRepeat=true;continue;}returnfalse;}returntrue;}boolCSSParserImpl::ParseBorderSpacing(){nsCSSValuexValue,yValue;if(!ParseNonNegativeVariant(xValue,VARIANT_HL|VARIANT_CALC,nullptr)){returnfalse;}// If we have one length, get the optional second length.// set the second value equal to the first.if(xValue.IsLengthUnit()||xValue.IsCalcUnit()){ParseNonNegativeVariant(yValue,VARIANT_LENGTH|VARIANT_CALC,nullptr);}if(!ExpectEndProperty()){returnfalse;}if(yValue==xValue||yValue.GetUnit()==eCSSUnit_Null){AppendValue(eCSSProperty_border_spacing,xValue);}else{nsCSSValuepair;pair.SetPairValue(xValue,yValue);AppendValue(eCSSProperty_border_spacing,pair);}returntrue;}boolCSSParserImpl::ParseBorderSide(constnsCSSPropertyaPropIDs[],boolaSetAllSides){constint32_tnumProps=3;nsCSSValuevalues[numProps];int32_tfound=ParseChoice(values,aPropIDs,numProps);if((found<1)||(false==ExpectEndProperty())){returnfalse;}if((found&1)==0){// Provide default border-widthvalues[0].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM,eCSSUnit_Enumerated);}if((found&2)==0){// Provide default border-stylevalues[1].SetIntValue(NS_STYLE_BORDER_STYLE_NONE,eCSSUnit_Enumerated);}if((found&4)==0){// text color will be usedvalues[2].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR,eCSSUnit_Enumerated);}if(aSetAllSides){staticconstnsCSSPropertykBorderSources[]={eCSSProperty_border_left_color_ltr_source,eCSSProperty_border_left_color_rtl_source,eCSSProperty_border_right_color_ltr_source,eCSSProperty_border_right_color_rtl_source,eCSSProperty_border_left_style_ltr_source,eCSSProperty_border_left_style_rtl_source,eCSSProperty_border_right_style_ltr_source,eCSSProperty_border_right_style_rtl_source,eCSSProperty_border_left_width_ltr_source,eCSSProperty_border_left_width_rtl_source,eCSSProperty_border_right_width_ltr_source,eCSSProperty_border_right_width_rtl_source,eCSSProperty_UNKNOWN};InitBoxPropsAsPhysical(kBorderSources);// Parsing "border" shorthand; set all four sides to the same thingfor(int32_tindex=0;index<4;index++){NS_ASSERTION(numProps==3,"This code needs updating");AppendValue(kBorderWidthIDs[index],values[0]);AppendValue(kBorderStyleIDs[index],values[1]);AppendValue(kBorderColorIDs[index],values[2]);}staticconstnsCSSPropertykBorderColorsProps[]={eCSSProperty_border_top_colors,eCSSProperty_border_right_colors,eCSSProperty_border_bottom_colors,eCSSProperty_border_left_colors};// Set the other properties that the border shorthand sets to their// initial values.nsCSSValueextraValue;switch(values[0].GetUnit()){caseeCSSUnit_Inherit:caseeCSSUnit_Initial:extraValue=values[0];// Set value of border-image properties to initial/inheritAppendValue(eCSSProperty_border_image_source,extraValue);AppendValue(eCSSProperty_border_image_slice,extraValue);AppendValue(eCSSProperty_border_image_width,extraValue);AppendValue(eCSSProperty_border_image_outset,extraValue);AppendValue(eCSSProperty_border_image_repeat,extraValue);break;default:extraValue.SetNoneValue();SetBorderImageInitialValues();break;}NS_FOR_CSS_SIDES(side){AppendValue(kBorderColorsProps[side],extraValue);}}else{// Just set our one sidefor(int32_tindex=0;index<numProps;index++){AppendValue(aPropIDs[index],values[index]);}}returntrue;}boolCSSParserImpl::ParseDirectionalBorderSide(constnsCSSPropertyaPropIDs[],int32_taSourceType){constint32_tnumProps=3;nsCSSValuevalues[numProps];int32_tfound=ParseChoice(values,aPropIDs,numProps);if((found<1)||(false==ExpectEndProperty())){returnfalse;}if((found&1)==0){// Provide default border-widthvalues[0].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM,eCSSUnit_Enumerated);}if((found&2)==0){// Provide default border-stylevalues[1].SetIntValue(NS_STYLE_BORDER_STYLE_NONE,eCSSUnit_Enumerated);}if((found&4)==0){// text color will be usedvalues[2].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR,eCSSUnit_Enumerated);}for(int32_tindex=0;index<numProps;index++){constnsCSSProperty*subprops=nsCSSProps::SubpropertyEntryFor(aPropIDs[index+numProps]);NS_ASSERTION(subprops[3]==eCSSProperty_UNKNOWN,"not box property with physical vs. logical cascading");AppendValue(subprops[0],values[index]);nsCSSValuetypeVal(aSourceType,eCSSUnit_Enumerated);AppendValue(subprops[1],typeVal);AppendValue(subprops[2],typeVal);}returntrue;}boolCSSParserImpl::ParseBorderStyle(){staticconstnsCSSPropertykBorderStyleSources[]={eCSSProperty_border_left_style_ltr_source,eCSSProperty_border_left_style_rtl_source,eCSSProperty_border_right_style_ltr_source,eCSSProperty_border_right_style_rtl_source,eCSSProperty_UNKNOWN};// do this now, in case 4 values weren't specifiedInitBoxPropsAsPhysical(kBorderStyleSources);returnParseBoxProperties(kBorderStyleIDs);}boolCSSParserImpl::ParseBorderWidth(){staticconstnsCSSPropertykBorderWidthSources[]={eCSSProperty_border_left_width_ltr_source,eCSSProperty_border_left_width_rtl_source,eCSSProperty_border_right_width_ltr_source,eCSSProperty_border_right_width_rtl_source,eCSSProperty_UNKNOWN};// do this now, in case 4 values weren't specifiedInitBoxPropsAsPhysical(kBorderWidthSources);returnParseBoxProperties(kBorderWidthIDs);}boolCSSParserImpl::ParseBorderColors(nsCSSPropertyaProperty){nsCSSValuevalue;if(ParseVariant(value,VARIANT_INHERIT|VARIANT_NONE,nullptr)){// 'inherit', 'initial', and 'none' are only allowed on their ownif(!ExpectEndProperty()){returnfalse;}}else{nsCSSValueList*cur=value.SetListValue();for(;;){if(!ParseVariant(cur->mValue,VARIANT_COLOR|VARIANT_KEYWORD,nsCSSProps::kBorderColorKTable)){returnfalse;}if(CheckEndProperty()){break;}cur->mNext=newnsCSSValueList;cur=cur->mNext;}}AppendValue(aProperty,value);returntrue;}// Parse the top level of a calc() expression.boolCSSParserImpl::ParseCalc(nsCSSValue&aValue,int32_taVariantMask){// Parsing calc expressions requires, in a number of cases, looking// for a token that is *either* a value of the property or a number.// This can be done without lookahead when we assume that the property// values cannot themselves be numbers.NS_ASSERTION(!(aVariantMask&VARIANT_NUMBER),"unexpected variant mask");NS_ABORT_IF_FALSE(aVariantMask!=0,"unexpected variant mask");boololdUnitlessLengthQuirk=mUnitlessLengthQuirk;mUnitlessLengthQuirk=false;// One-iteration loop so we can break to the error-handling case.do{// The toplevel of a calc() is always an nsCSSValue::Array of length 1.nsRefPtr<nsCSSValue::Array>arr=nsCSSValue::Array::Create(1);if(!ParseCalcAdditiveExpression(arr->Item(0),aVariantMask))break;if(!ExpectSymbol(')',true))break;aValue.SetArrayValue(arr,eCSSUnit_Calc);mUnitlessLengthQuirk=oldUnitlessLengthQuirk;returntrue;}while(false);SkipUntil(')');mUnitlessLengthQuirk=oldUnitlessLengthQuirk;returnfalse;}// We optimize away the <value-expression> production given that// ParseVariant consumes initial whitespace and we call// ExpectSymbol(')') with true for aSkipWS.// * If aVariantMask is VARIANT_NUMBER, this function parses the// <number-additive-expression> production.// * If aVariantMask does not contain VARIANT_NUMBER, this function// parses the <value-additive-expression> production.// * Otherwise (VARIANT_NUMBER and other bits) this function parses// whichever one of the productions matches ***and modifies// aVariantMask*** to reflect which one it has parsed by either// removing VARIANT_NUMBER or removing all other bits.// It does so iteratively, but builds the correct recursive// data structure.boolCSSParserImpl::ParseCalcAdditiveExpression(nsCSSValue&aValue,int32_t&aVariantMask){NS_ABORT_IF_FALSE(aVariantMask!=0,"unexpected variant mask");nsCSSValue*storage=&aValue;for(;;){boolhaveWS;if(!ParseCalcMultiplicativeExpression(*storage,aVariantMask,&haveWS))returnfalse;if(!haveWS||!GetToken(false))returntrue;nsCSSUnitunit;if(mToken.IsSymbol('+')){unit=eCSSUnit_Calc_Plus;}elseif(mToken.IsSymbol('-')){unit=eCSSUnit_Calc_Minus;}else{UngetToken();returntrue;}if(!RequireWhitespace())returnfalse;nsRefPtr<nsCSSValue::Array>arr=nsCSSValue::Array::Create(2);arr->Item(0)=aValue;storage=&arr->Item(1);aValue.SetArrayValue(arr,unit);}}structReduceNumberCalcOps:publicmozilla::css::BasicFloatCalcOps,publicmozilla::css::CSSValueInputCalcOps{result_typeComputeLeafValue(constnsCSSValue&aValue){NS_ABORT_IF_FALSE(aValue.GetUnit()==eCSSUnit_Number,"unexpected unit");returnaValue.GetFloatValue();}floatComputeNumber(constnsCSSValue&aValue){returnmozilla::css::ComputeCalc(aValue,*this);}};// * If aVariantMask is VARIANT_NUMBER, this function parses the// <number-multiplicative-expression> production.// * If aVariantMask does not contain VARIANT_NUMBER, this function// parses the <value-multiplicative-expression> production.// * Otherwise (VARIANT_NUMBER and other bits) this function parses// whichever one of the productions matches ***and modifies// aVariantMask*** to reflect which one it has parsed by either// removing VARIANT_NUMBER or removing all other bits.// It does so iteratively, but builds the correct recursive data// structure.// This function always consumes *trailing* whitespace when it returns// true; whether there was any such whitespace is returned in the// aHadFinalWS parameter.boolCSSParserImpl::ParseCalcMultiplicativeExpression(nsCSSValue&aValue,int32_t&aVariantMask,bool*aHadFinalWS){NS_ABORT_IF_FALSE(aVariantMask!=0,"unexpected variant mask");boolgotValue=false;// already got the part with the unitboolafterDivision=false;nsCSSValue*storage=&aValue;for(;;){int32_tvariantMask;if(afterDivision||gotValue){variantMask=VARIANT_NUMBER;}else{variantMask=aVariantMask|VARIANT_NUMBER;}if(!ParseCalcTerm(*storage,variantMask))returnfalse;NS_ABORT_IF_FALSE(variantMask!=0,"ParseCalcTerm did not set variantMask appropriately");NS_ABORT_IF_FALSE(!(variantMask&VARIANT_NUMBER)||!(variantMask&~int32_t(VARIANT_NUMBER)),"ParseCalcTerm did not set variantMask appropriately");if(variantMask&VARIANT_NUMBER){// Simplify the value immediately so we can check for division by// zero.ReduceNumberCalcOpsops;floatnumber=mozilla::css::ComputeCalc(*storage,ops);if(number==0.0&&afterDivision)returnfalse;storage->SetFloatValue(number,eCSSUnit_Number);}else{gotValue=true;if(storage!=&aValue){// Simplify any numbers in the Times_L position (which are// not simplified by the check above).NS_ABORT_IF_FALSE(storage==&aValue.GetArrayValue()->Item(1),"unexpected relationship to current storage");nsCSSValue&leftValue=aValue.GetArrayValue()->Item(0);ReduceNumberCalcOpsops;floatnumber=mozilla::css::ComputeCalc(leftValue,ops);leftValue.SetFloatValue(number,eCSSUnit_Number);}}boolhadWS=RequireWhitespace();if(!GetToken(false)){*aHadFinalWS=hadWS;break;}nsCSSUnitunit;if(mToken.IsSymbol('*')){unit=gotValue?eCSSUnit_Calc_Times_R:eCSSUnit_Calc_Times_L;afterDivision=false;}elseif(mToken.IsSymbol('/')){unit=eCSSUnit_Calc_Divided;afterDivision=true;}else{UngetToken();*aHadFinalWS=hadWS;break;}nsRefPtr<nsCSSValue::Array>arr=nsCSSValue::Array::Create(2);arr->Item(0)=aValue;storage=&arr->Item(1);aValue.SetArrayValue(arr,unit);}// Adjust aVariantMask (see comments above function) to reflect which// option we took.if(aVariantMask&VARIANT_NUMBER){if(gotValue){aVariantMask&=~int32_t(VARIANT_NUMBER);}else{aVariantMask=VARIANT_NUMBER;}}else{if(!gotValue){// We had to find a value, but we didn't.returnfalse;}}returntrue;}// * If aVariantMask is VARIANT_NUMBER, this function parses the// <number-term> production.// * If aVariantMask does not contain VARIANT_NUMBER, this function// parses the <value-term> production.// * Otherwise (VARIANT_NUMBER and other bits) this function parses// whichever one of the productions matches ***and modifies// aVariantMask*** to reflect which one it has parsed by either// removing VARIANT_NUMBER or removing all other bits.boolCSSParserImpl::ParseCalcTerm(nsCSSValue&aValue,int32_t&aVariantMask){NS_ABORT_IF_FALSE(aVariantMask!=0,"unexpected variant mask");if(!GetToken(true))returnfalse;// Either an additive expression in parentheses...if(mToken.IsSymbol('(')){if(!ParseCalcAdditiveExpression(aValue,aVariantMask)||!ExpectSymbol(')',true)){SkipUntil(')');returnfalse;}returntrue;}// ... or just a valueUngetToken();// Always pass VARIANT_NUMBER to ParseVariant so that unitless zero// always gets picked up if(!ParseVariant(aValue,aVariantMask|VARIANT_NUMBER,nullptr)){returnfalse;}// ...and do the VARIANT_NUMBER check ourselves.if(!(aVariantMask&VARIANT_NUMBER)&&aValue.GetUnit()==eCSSUnit_Number){returnfalse;}// If we did the value parsing, we need to adjust aVariantMask to// reflect which option we took (see above).if(aVariantMask&VARIANT_NUMBER){if(aValue.GetUnit()==eCSSUnit_Number){aVariantMask=VARIANT_NUMBER;}else{aVariantMask&=~int32_t(VARIANT_NUMBER);}}returntrue;}// This function consumes all consecutive whitespace and returns whether// there was any.boolCSSParserImpl::RequireWhitespace(){if(!GetToken(false))returnfalse;if(mToken.mType!=eCSSToken_Whitespace){UngetToken();returnfalse;}// Skip any additional whitespace tokens.if(GetToken(true)){UngetToken();}returntrue;}boolCSSParserImpl::ParseRect(nsCSSPropertyaPropID){if(!GetToken(true)){returnfalse;}nsCSSValueval;if(mToken.mType==eCSSToken_Ident){nsCSSKeywordkeyword=nsCSSKeywords::LookupKeyword(mToken.mIdent);switch(keyword){caseeCSSKeyword_auto:if(!ExpectEndProperty()){returnfalse;}val.SetAutoValue();break;caseeCSSKeyword_inherit:if(!ExpectEndProperty()){returnfalse;}val.SetInheritValue();break;caseeCSSKeyword_initial:caseeCSSKeyword__moz_initial:if(!ExpectEndProperty()){returnfalse;}val.SetInitialValue();break;default:UngetToken();returnfalse;}}elseif(mToken.mType==eCSSToken_Function&&mToken.mIdent.LowerCaseEqualsLiteral("rect")){nsCSSRect&rect=val.SetRectValue();booluseCommas;NS_FOR_CSS_SIDES(side){if(!ParseVariant(rect.*(nsCSSRect::sides[side]),VARIANT_AL,nullptr)){returnfalse;}if(side==0){useCommas=ExpectSymbol(',',true);}elseif(useCommas&&side<3){// Skip optional commas between elements, but only if the first// separator was a comma.if(!ExpectSymbol(',',true)){returnfalse;}}}if(!ExpectSymbol(')',true)){returnfalse;}if(!ExpectEndProperty()){returnfalse;}}else{UngetToken();returnfalse;}AppendValue(aPropID,val);returntrue;}boolCSSParserImpl::ParseColumns(){// We use a similar "fake value" hack to ParseListStyle, because// "auto" is acceptable for both column-count and column-width.// If the fake "auto" value is found, and one of the real values isn't,// that means the fake auto value is meant for the real value we didn't// find.staticconstnsCSSPropertycolumnIDs[]={eCSSPropertyExtra_x_auto_value,eCSSProperty__moz_column_count,eCSSProperty__moz_column_width};constint32_tnumProps=NS_ARRAY_LENGTH(columnIDs);nsCSSValuevalues[numProps];int32_tfound=ParseChoice(values,columnIDs,numProps);if(found<1||!ExpectEndProperty()){returnfalse;}if((found&(1|2|4))==(1|2|4)&&values[0].GetUnit()==eCSSUnit_Auto){// We filled all 3 values, which is invalidreturnfalse;}if((found&2)==0){// Provide auto column-countvalues[1].SetAutoValue();}if((found&4)==0){// Provide auto column-widthvalues[2].SetAutoValue();}// Start at index 1 to skip the fake auto value.for(int32_tindex=1;index<numProps;index++){AppendValue(columnIDs[index],values[index]);}returntrue;}#define VARIANT_CONTENT (VARIANT_STRING | VARIANT_URL | VARIANT_COUNTER | VARIANT_ATTR | \ VARIANT_KEYWORD)boolCSSParserImpl::ParseContent(){// We need to divide the 'content' keywords into two classes for// ParseVariant's sake, so we can't just use nsCSSProps::kContentKTable.staticconstint32_tkContentListKWs[]={eCSSKeyword_open_quote,NS_STYLE_CONTENT_OPEN_QUOTE,eCSSKeyword_close_quote,NS_STYLE_CONTENT_CLOSE_QUOTE,eCSSKeyword_no_open_quote,NS_STYLE_CONTENT_NO_OPEN_QUOTE,eCSSKeyword_no_close_quote,NS_STYLE_CONTENT_NO_CLOSE_QUOTE,eCSSKeyword_UNKNOWN,-1};staticconstint32_tkContentSolitaryKWs[]={eCSSKeyword__moz_alt_content,NS_STYLE_CONTENT_ALT_CONTENT,eCSSKeyword_UNKNOWN,-1};// Verify that these two lists add up to the size of// nsCSSProps::kContentKTable.NS_ABORT_IF_FALSE(nsCSSProps::kContentKTable[ArrayLength(kContentListKWs)+ArrayLength(kContentSolitaryKWs)-4]==eCSSKeyword_UNKNOWN&&nsCSSProps::kContentKTable[ArrayLength(kContentListKWs)+ArrayLength(kContentSolitaryKWs)-3]==-1,"content keyword tables out of sync");nsCSSValuevalue;if(ParseVariant(value,VARIANT_HMK|VARIANT_NONE,kContentSolitaryKWs)){// 'inherit', 'initial', 'normal', 'none', and 'alt-content' must be aloneif(!ExpectEndProperty()){returnfalse;}}else{nsCSSValueList*cur=value.SetListValue();for(;;){if(!ParseVariant(cur->mValue,VARIANT_CONTENT,kContentListKWs)){returnfalse;}if(CheckEndProperty()){break;}cur->mNext=newnsCSSValueList;cur=cur->mNext;}}AppendValue(eCSSProperty_content,value);returntrue;}boolCSSParserImpl::ParseCounterData(nsCSSPropertyaPropID){nsCSSValuevalue;if(!ParseVariant(value,VARIANT_INHERIT|VARIANT_NONE,nullptr)){if(!GetToken(true)||mToken.mType!=eCSSToken_Ident){returnfalse;}nsCSSValuePairList*cur=value.SetPairListValue();for(;;){cur->mXValue.SetStringValue(mToken.mIdent,eCSSUnit_Ident);if(!GetToken(true)){break;}if(mToken.mType==eCSSToken_Number&&mToken.mIntegerValid){cur->mYValue.SetIntValue(mToken.mInteger,eCSSUnit_Integer);}else{UngetToken();}if(CheckEndProperty()){break;}if(!GetToken(true)||mToken.mType!=eCSSToken_Ident){returnfalse;}cur->mNext=newnsCSSValuePairList;cur=cur->mNext;}}AppendValue(aPropID,value);returntrue;}boolCSSParserImpl::ParseCursor(){nsCSSValuevalue;if(ParseVariant(value,VARIANT_INHERIT,nullptr)){// 'inherit' and 'initial' must be aloneif(!ExpectEndProperty()){returnfalse;}}else{nsCSSValueList*cur=value.SetListValue();for(;;){if(!ParseVariant(cur->mValue,VARIANT_UK,nsCSSProps::kCursorKTable)){returnfalse;}if(cur->mValue.GetUnit()!=eCSSUnit_URL){// keyword must be lastif(ExpectEndProperty()){break;}returnfalse;}// We have a URL, so make a value array with three values.nsRefPtr<nsCSSValue::Array>val=nsCSSValue::Array::Create(3);val->Item(0)=cur->mValue;// Parse optional x and y position of cursor hotspot (css3-ui).if(ParseVariant(val->Item(1),VARIANT_NUMBER,nullptr)){// If we have one number, we must have two.if(!ParseVariant(val->Item(2),VARIANT_NUMBER,nullptr)){returnfalse;}}cur->mValue.SetArrayValue(val,eCSSUnit_Array);if(!ExpectSymbol(',',true)){// url must not be lastreturnfalse;}cur->mNext=newnsCSSValueList;cur=cur->mNext;}}AppendValue(eCSSProperty_cursor,value);returntrue;}boolCSSParserImpl::ParseFont(){staticconstnsCSSPropertyfontIDs[]={eCSSProperty_font_style,eCSSProperty_font_variant,eCSSProperty_font_weight};nsCSSValuefamily;if(ParseVariant(family,VARIANT_HK,nsCSSProps::kFontKTable)){if(ExpectEndProperty()){if(eCSSUnit_Inherit==family.GetUnit()||eCSSUnit_Initial==family.GetUnit()){AppendValue(eCSSProperty__x_system_font,nsCSSValue(eCSSUnit_None));AppendValue(eCSSProperty_font_family,family);AppendValue(eCSSProperty_font_style,family);AppendValue(eCSSProperty_font_variant,family);AppendValue(eCSSProperty_font_weight,family);AppendValue(eCSSProperty_font_size,family);AppendValue(eCSSProperty_line_height,family);AppendValue(eCSSProperty_font_stretch,family);AppendValue(eCSSProperty_font_size_adjust,family);AppendValue(eCSSProperty_font_feature_settings,family);AppendValue(eCSSProperty_font_language_override,family);}else{AppendValue(eCSSProperty__x_system_font,family);nsCSSValuesystemFont(eCSSUnit_System_Font);AppendValue(eCSSProperty_font_family,systemFont);AppendValue(eCSSProperty_font_style,systemFont);AppendValue(eCSSProperty_font_variant,systemFont);AppendValue(eCSSProperty_font_weight,systemFont);AppendValue(eCSSProperty_font_size,systemFont);AppendValue(eCSSProperty_line_height,systemFont);AppendValue(eCSSProperty_font_stretch,systemFont);AppendValue(eCSSProperty_font_size_adjust,systemFont);AppendValue(eCSSProperty_font_feature_settings,systemFont);AppendValue(eCSSProperty_font_language_override,systemFont);}returntrue;}returnfalse;}// Get optional font-style, font-variant and font-weight (in any order)constint32_tnumProps=3;nsCSSValuevalues[numProps];int32_tfound=ParseChoice(values,fontIDs,numProps);if((found<0)||(eCSSUnit_Inherit==values[0].GetUnit())||(eCSSUnit_Initial==values[0].GetUnit())){// illegal datareturnfalse;}if((found&1)==0){// Provide default font-stylevalues[0].SetIntValue(NS_FONT_STYLE_NORMAL,eCSSUnit_Enumerated);}if((found&2)==0){// Provide default font-variantvalues[1].SetIntValue(NS_FONT_VARIANT_NORMAL,eCSSUnit_Enumerated);}if((found&4)==0){// Provide default font-weightvalues[2].SetIntValue(NS_FONT_WEIGHT_NORMAL,eCSSUnit_Enumerated);}// Get mandatory font-sizensCSSValuesize;if(!ParseVariant(size,VARIANT_KEYWORD|VARIANT_LP,nsCSSProps::kFontSizeKTable)){returnfalse;}// Get optional "/" line-heightnsCSSValuelineHeight;if(ExpectSymbol('/',true)){if(!ParseNonNegativeVariant(lineHeight,VARIANT_NUMBER|VARIANT_LP|VARIANT_NORMAL,nullptr)){returnfalse;}}else{lineHeight.SetNormalValue();}// Get final mandatory font-familynsAutoParseCompoundPropertycompound(this);if(ParseFamily(family)){if((eCSSUnit_Inherit!=family.GetUnit())&&(eCSSUnit_Initial!=family.GetUnit())&&ExpectEndProperty()){AppendValue(eCSSProperty__x_system_font,nsCSSValue(eCSSUnit_None));AppendValue(eCSSProperty_font_family,family);AppendValue(eCSSProperty_font_style,values[0]);AppendValue(eCSSProperty_font_variant,values[1]);AppendValue(eCSSProperty_font_weight,values[2]);AppendValue(eCSSProperty_font_size,size);AppendValue(eCSSProperty_line_height,lineHeight);AppendValue(eCSSProperty_font_stretch,nsCSSValue(NS_FONT_STRETCH_NORMAL,eCSSUnit_Enumerated));AppendValue(eCSSProperty_font_size_adjust,nsCSSValue(eCSSUnit_None));AppendValue(eCSSProperty_font_feature_settings,nsCSSValue(eCSSUnit_Normal));AppendValue(eCSSProperty_font_language_override,nsCSSValue(eCSSUnit_Normal));returntrue;}}returnfalse;}boolCSSParserImpl::ParseFontWeight(nsCSSValue&aValue){if(ParseVariant(aValue,VARIANT_HKI|VARIANT_SYSFONT,nsCSSProps::kFontWeightKTable)){if(eCSSUnit_Integer==aValue.GetUnit()){// ensure unit valueint32_tintValue=aValue.GetIntValue();if((100<=intValue)&&(intValue<=900)&&(0==(intValue%100))){returntrue;}else{UngetToken();returnfalse;}}returntrue;}returnfalse;}boolCSSParserImpl::ParseOneFamily(nsAString&aFamily,bool&aOneKeyword){if(!GetToken(true))returnfalse;nsCSSToken*tk=&mToken;aOneKeyword=false;if(eCSSToken_Ident==tk->mType){aOneKeyword=true;aFamily.Append(tk->mIdent);for(;;){if(!GetToken(false))break;if(eCSSToken_Ident==tk->mType){aOneKeyword=false;aFamily.Append(tk->mIdent);}elseif(eCSSToken_Whitespace==tk->mType){// Lookahead one token and drop whitespace if we are ending the// font name.if(!GetToken(true))break;UngetToken();if(eCSSToken_Ident==tk->mType)aFamily.Append(PRUnichar(' '));elsebreak;}else{UngetToken();break;}}returntrue;}elseif(eCSSToken_String==tk->mType){aFamily.Append(tk->mSymbol);// replace the quotesaFamily.Append(tk->mIdent);// XXX What if it had escaped quotes?aFamily.Append(tk->mSymbol);returntrue;}else{UngetToken();returnfalse;}}boolCSSParserImpl::ParseFamily(nsCSSValue&aValue){nsAutoStringfamily;boolsingle;// keywords only have meaning in the first positionif(!ParseOneFamily(family,single))returnfalse;// check for keywords, but only when keywords appear by themselves// i.e. not in compounds such as font-family: default blah;if(single){nsCSSKeywordkeyword=nsCSSKeywords::LookupKeyword(family);if(keyword==eCSSKeyword_inherit){aValue.SetInheritValue();returntrue;}// 605231 - don't parse unquoted 'default' reserved keywordif(keyword==eCSSKeyword_default){returnfalse;}if(keyword==eCSSKeyword__moz_initial||keyword==eCSSKeyword_initial){aValue.SetInitialValue();returntrue;}if(keyword==eCSSKeyword__moz_use_system_font&&!IsParsingCompoundProperty()){aValue.SetSystemFontValue();returntrue;}}for(;;){if(!ExpectSymbol(',',true))break;family.Append(PRUnichar(','));nsAutoStringnextFamily;if(!ParseOneFamily(nextFamily,single))returnfalse;// at this point unquoted keywords are not allowed// as font family names but can appear within namesif(single){nsCSSKeywordkeyword=nsCSSKeywords::LookupKeyword(nextFamily);switch(keyword){caseeCSSKeyword_inherit:caseeCSSKeyword_initial:caseeCSSKeyword_default:caseeCSSKeyword__moz_initial:caseeCSSKeyword__moz_use_system_font:returnfalse;default:break;}}family.Append(nextFamily);}if(family.IsEmpty()){returnfalse;}aValue.SetStringValue(family,eCSSUnit_Families);returntrue;}// src: ( uri-src | local-src ) (',' ( uri-src | local-src ) )*// uri-src: uri [ 'format(' string ( ',' string )* ')' ]// local-src: 'local(' ( string | ident ) ')'boolCSSParserImpl::ParseFontSrc(nsCSSValue&aValue){// could we maybe turn nsCSSValue::Array into InfallibleTArray<nsCSSValue>?InfallibleTArray<nsCSSValue>values;nsCSSValuecur;for(;;){if(!GetToken(true))break;if(mToken.mType==eCSSToken_URL){SetValueToURL(cur,mToken.mIdent);values.AppendElement(cur);if(!ParseFontSrcFormat(values))returnfalse;}elseif(mToken.mType==eCSSToken_Function&&mToken.mIdent.LowerCaseEqualsLiteral("local")){// css3-fonts does not specify a formal grammar for local().// The text permits both unquoted identifiers and quoted// strings. We resolve this ambiguity in the spec by// assuming that the appropriate production is a single// <family-name>, possibly surrounded by whitespace.nsAutoStringfamily;boolsingle;if(!ParseOneFamily(family,single)){SkipUntil(')');returnfalse;}if(!ExpectSymbol(')',true)){SkipUntil(')');returnfalse;}// the style parameters to the nsFont constructor are ignored,// because it's only being used to call EnumerateFamiliesnsFontfont(family,0,0,0,0,0,0);ExtractFirstFamilyDatadat;font.EnumerateFamilies(ExtractFirstFamily,(void*)&dat);if(!dat.mGood)returnfalse;cur.SetStringValue(dat.mFamilyName,eCSSUnit_Local_Font);values.AppendElement(cur);}else{// We don't know what to do with this token; unget it and error outUngetToken();returnfalse;}if(!ExpectSymbol(',',true))break;}if(values.Length()==0)returnfalse;nsRefPtr<nsCSSValue::Array>srcVals=nsCSSValue::Array::Create(values.Length());uint32_ti;for(i=0;i<values.Length();i++)srcVals->Item(i)=values[i];aValue.SetArrayValue(srcVals,eCSSUnit_Array);returntrue;}boolCSSParserImpl::ParseFontSrcFormat(InfallibleTArray<nsCSSValue>&values){if(!GetToken(true))returntrue;// EOF harmless hereif(mToken.mType!=eCSSToken_Function||!mToken.mIdent.LowerCaseEqualsLiteral("format")){UngetToken();returntrue;}do{if(!GetToken(true))returnfalse;// EOF - no need for SkipUntilif(mToken.mType!=eCSSToken_String){UngetToken();SkipUntil(')');returnfalse;}nsCSSValuecur(mToken.mIdent,eCSSUnit_Font_Format);values.AppendElement(cur);}while(ExpectSymbol(',',true));if(!ExpectSymbol(')',true)){SkipUntil(')');returnfalse;}returntrue;}// font-ranges: urange ( ',' urange )*boolCSSParserImpl::ParseFontRanges(nsCSSValue&aValue){InfallibleTArray<uint32_t>ranges;for(;;){if(!GetToken(true))break;if(mToken.mType!=eCSSToken_URange){UngetToken();break;}// An invalid range token is a parsing error, causing the entire// descriptor to be ignored.if(!mToken.mIntegerValid)returnfalse;uint32_tlow=mToken.mInteger;uint32_thigh=mToken.mInteger2;// A range that descends, or a range that is entirely outside the// current range of Unicode (U+0-10FFFF) is ignored, but does not// invalidate the descriptor. A range that straddles the high end// is clipped.if(low<=0x10FFFF&&low<=high){if(high>0x10FFFF)high=0x10FFFF;ranges.AppendElement(low);ranges.AppendElement(high);}if(!ExpectSymbol(',',true))break;}if(ranges.Length()==0)returnfalse;nsRefPtr<nsCSSValue::Array>srcVals=nsCSSValue::Array::Create(ranges.Length());for(uint32_ti=0;i<ranges.Length();i++)srcVals->Item(i).SetIntValue(ranges[i],eCSSUnit_Integer);aValue.SetArrayValue(srcVals,eCSSUnit_Array);returntrue;}// font-feature-settings: normal | <feature-tag-value> [, <feature-tag-value>]*// <feature-tag-value> = <string> [ <integer> | on | off ]?// minimum - "tagx", "tagy", "tagz"// edge error case - "tagx" on 1, "tagx" "tagy", "tagx" -1, "tagx" big// pair value is always x = string, y = int// font feature tags must be four ASCII characters#define FEATURE_TAG_LENGTH 4staticboolValidFontFeatureTag(constnsString&aTag){if(aTag.Length()!=FEATURE_TAG_LENGTH){returnfalse;}uint32_ti;for(i=0;i<FEATURE_TAG_LENGTH;i++){uint32_tch=aTag[i];if(ch<0x20||ch>0x7e){returnfalse;}}returntrue;}boolCSSParserImpl::ParseFontFeatureSettings(nsCSSValue&aValue){if(ParseVariant(aValue,VARIANT_INHERIT|VARIANT_NORMAL,nullptr)){returntrue;}nsCSSValuePairList*cur=aValue.SetPairListValue();for(;;){// feature tagif(!GetToken(true)){returnfalse;}if(mToken.mType!=eCSSToken_String||!ValidFontFeatureTag(mToken.mIdent)){UngetToken();returnfalse;}cur->mXValue.SetStringValue(mToken.mIdent,eCSSUnit_String);if(!GetToken(true)){cur->mYValue.SetIntValue(1,eCSSUnit_Integer);break;}// optional value or on/off keywordif(mToken.mType==eCSSToken_Number&&mToken.mIntegerValid&&mToken.mInteger>=0){cur->mYValue.SetIntValue(mToken.mInteger,eCSSUnit_Integer);}elseif(mToken.mType==eCSSToken_Ident&&mToken.mIdent.LowerCaseEqualsLiteral("on")){cur->mYValue.SetIntValue(1,eCSSUnit_Integer);}elseif(mToken.mType==eCSSToken_Ident&&mToken.mIdent.LowerCaseEqualsLiteral("off")){cur->mYValue.SetIntValue(0,eCSSUnit_Integer);}else{// something other than value/on/off, set default valuecur->mYValue.SetIntValue(1,eCSSUnit_Integer);UngetToken();}if(!ExpectSymbol(',',true)){break;}cur->mNext=newnsCSSValuePairList;cur=cur->mNext;}returntrue;}boolCSSParserImpl::ParseListStyle(){// 'list-style' can accept 'none' for two different subproperties,// 'list-style-type' and 'list-style-position'. In order to accept// 'none' as the value of either but still allow another value for// either, we need to ensure that the first 'none' we find gets// allocated to a dummy property instead.staticconstnsCSSPropertylistStyleIDs[]={eCSSPropertyExtra_x_none_value,eCSSProperty_list_style_type,eCSSProperty_list_style_position,eCSSProperty_list_style_image};nsCSSValuevalues[NS_ARRAY_LENGTH(listStyleIDs)];int32_tfound=ParseChoice(values,listStyleIDs,ArrayLength(listStyleIDs));if(found<1||!ExpectEndProperty()){returnfalse;}if((found&(1|2|8))==(1|2|8)){if(values[0].GetUnit()==eCSSUnit_None){// We found a 'none' plus another value for both of// 'list-style-type' and 'list-style-image'. This is a parse// error, since the 'none' has to count for at least one of them.returnfalse;}else{NS_ASSERTION(found==(1|2|4|8)&&values[0]==values[1]&&values[0]==values[2]&&values[0]==values[3],"should be a special value");}}// Provide default valuesif((found&2)==0){if(found&1){values[1].SetIntValue(NS_STYLE_LIST_STYLE_NONE,eCSSUnit_Enumerated);}else{values[1].SetIntValue(NS_STYLE_LIST_STYLE_DISC,eCSSUnit_Enumerated);}}if((found&4)==0){values[2].SetIntValue(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE,eCSSUnit_Enumerated);}if((found&8)==0){values[3].SetNoneValue();}// Start at 1 to avoid appending fake value.for(uint32_tindex=1;index<ArrayLength(listStyleIDs);++index){AppendValue(listStyleIDs[index],values[index]);}returntrue;}boolCSSParserImpl::ParseMargin(){staticconstnsCSSPropertykMarginSideIDs[]={eCSSProperty_margin_top,eCSSProperty_margin_right_value,eCSSProperty_margin_bottom,eCSSProperty_margin_left_value};staticconstnsCSSPropertykMarginSources[]={eCSSProperty_margin_left_ltr_source,eCSSProperty_margin_left_rtl_source,eCSSProperty_margin_right_ltr_source,eCSSProperty_margin_right_rtl_source,eCSSProperty_UNKNOWN};// do this now, in case 4 values weren't specifiedInitBoxPropsAsPhysical(kMarginSources);returnParseBoxProperties(kMarginSideIDs);}boolCSSParserImpl::ParseMarks(nsCSSValue&aValue){if(ParseVariant(aValue,VARIANT_HK,nsCSSProps::kPageMarksKTable)){if(eCSSUnit_Enumerated==aValue.GetUnit()){if(NS_STYLE_PAGE_MARKS_NONE!=aValue.GetIntValue()&&false==CheckEndProperty()){nsCSSValuesecond;if(ParseEnum(second,nsCSSProps::kPageMarksKTable)){// 'none' keyword in conjuction with others is not allowedif(NS_STYLE_PAGE_MARKS_NONE!=second.GetIntValue()){aValue.SetIntValue(aValue.GetIntValue()|second.GetIntValue(),eCSSUnit_Enumerated);returntrue;}}returnfalse;}}returntrue;}returnfalse;}boolCSSParserImpl::ParseOutline(){constint32_tnumProps=3;staticconstnsCSSPropertykOutlineIDs[]={eCSSProperty_outline_color,eCSSProperty_outline_style,eCSSProperty_outline_width};nsCSSValuevalues[numProps];int32_tfound=ParseChoice(values,kOutlineIDs,numProps);if((found<1)||(false==ExpectEndProperty())){returnfalse;}// Provide default valuesif((found&1)==0){// Provide default outline-colorvalues[0].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR,eCSSUnit_Enumerated);}if((found&2)==0){// Provide default outline-stylevalues[1].SetIntValue(NS_STYLE_BORDER_STYLE_NONE,eCSSUnit_Enumerated);}if((found&4)==0){// Provide default outline-widthvalues[2].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM,eCSSUnit_Enumerated);}int32_tindex;for(index=0;index<numProps;index++){AppendValue(kOutlineIDs[index],values[index]);}returntrue;}boolCSSParserImpl::ParseOverflow(){nsCSSValueoverflow;if(!ParseVariant(overflow,VARIANT_HK,nsCSSProps::kOverflowKTable)||!ExpectEndProperty())returnfalse;nsCSSValueoverflowX(overflow);nsCSSValueoverflowY(overflow);if(eCSSUnit_Enumerated==overflow.GetUnit())switch(overflow.GetIntValue()){caseNS_STYLE_OVERFLOW_SCROLLBARS_HORIZONTAL:overflowX.SetIntValue(NS_STYLE_OVERFLOW_SCROLL,eCSSUnit_Enumerated);overflowY.SetIntValue(NS_STYLE_OVERFLOW_HIDDEN,eCSSUnit_Enumerated);break;caseNS_STYLE_OVERFLOW_SCROLLBARS_VERTICAL:overflowX.SetIntValue(NS_STYLE_OVERFLOW_HIDDEN,eCSSUnit_Enumerated);overflowY.SetIntValue(NS_STYLE_OVERFLOW_SCROLL,eCSSUnit_Enumerated);break;}AppendValue(eCSSProperty_overflow_x,overflowX);AppendValue(eCSSProperty_overflow_y,overflowY);returntrue;}boolCSSParserImpl::ParsePadding(){staticconstnsCSSPropertykPaddingSideIDs[]={eCSSProperty_padding_top,eCSSProperty_padding_right_value,eCSSProperty_padding_bottom,eCSSProperty_padding_left_value};staticconstnsCSSPropertykPaddingSources[]={eCSSProperty_padding_left_ltr_source,eCSSProperty_padding_left_rtl_source,eCSSProperty_padding_right_ltr_source,eCSSProperty_padding_right_rtl_source,eCSSProperty_UNKNOWN};// do this now, in case 4 values weren't specifiedInitBoxPropsAsPhysical(kPaddingSources);returnParseBoxProperties(kPaddingSideIDs);}boolCSSParserImpl::ParseQuotes(){nsCSSValuevalue;if(!ParseVariant(value,VARIANT_HOS,nullptr)){returnfalse;}if(value.GetUnit()!=eCSSUnit_String){if(!ExpectEndProperty()){returnfalse;}}else{nsCSSValueopen=value;nsCSSValuePairList*quotes=value.SetPairListValue();for(;;){quotes->mXValue=open;// get mandatory closeif(!ParseVariant(quotes->mYValue,VARIANT_STRING,nullptr)){returnfalse;}if(CheckEndProperty()){break;}// look for another openif(!ParseVariant(open,VARIANT_STRING,nullptr)){returnfalse;}quotes->mNext=newnsCSSValuePairList;quotes=quotes->mNext;}}AppendValue(eCSSProperty_quotes,value);returntrue;}boolCSSParserImpl::ParseSize(){nsCSSValuewidth,height;if(!ParseVariant(width,VARIANT_AHKL,nsCSSProps::kPageSizeKTable)){returnfalse;}if(width.IsLengthUnit()){ParseVariant(height,VARIANT_LENGTH,nullptr);}if(!ExpectEndProperty()){returnfalse;}if(width==height||height.GetUnit()==eCSSUnit_Null){AppendValue(eCSSProperty_size,width);}else{nsCSSValuepair;pair.SetPairValue(width,height);AppendValue(eCSSProperty_size,pair);}returntrue;}boolCSSParserImpl::ParseTextDecoration(){enum{eDecorationNone=NS_STYLE_TEXT_DECORATION_LINE_NONE,eDecorationUnderline=NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,eDecorationOverline=NS_STYLE_TEXT_DECORATION_LINE_OVERLINE,eDecorationLineThrough=NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH,eDecorationBlink=NS_STYLE_TEXT_DECORATION_LINE_BLINK,eDecorationPrefAnchors=NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS};MOZ_STATIC_ASSERT((eDecorationNone^eDecorationUnderline^eDecorationOverline^eDecorationLineThrough^eDecorationBlink^eDecorationPrefAnchors)==(eDecorationNone|eDecorationUnderline|eDecorationOverline|eDecorationLineThrough|eDecorationBlink|eDecorationPrefAnchors),"text decoration constants need to be bitmasks");staticconstint32_tkTextDecorationKTable[]={eCSSKeyword_none,eDecorationNone,eCSSKeyword_underline,eDecorationUnderline,eCSSKeyword_overline,eDecorationOverline,eCSSKeyword_line_through,eDecorationLineThrough,eCSSKeyword_blink,eDecorationBlink,eCSSKeyword__moz_anchor_decoration,eDecorationPrefAnchors,eCSSKeyword_UNKNOWN,-1};nsCSSValuevalue;if(!ParseVariant(value,VARIANT_HK,kTextDecorationKTable)){returnfalse;}nsCSSValueblink,line,style,color;switch(value.GetUnit()){caseeCSSUnit_Enumerated:{// We shouldn't accept decoration line style and color via// text-decoration.color.SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR,eCSSUnit_Enumerated);style.SetIntValue(NS_STYLE_TEXT_DECORATION_STYLE_SOLID,eCSSUnit_Enumerated);int32_tintValue=value.GetIntValue();if(intValue==eDecorationNone){blink.SetIntValue(NS_STYLE_TEXT_BLINK_NONE,eCSSUnit_Enumerated);line.SetIntValue(NS_STYLE_TEXT_DECORATION_LINE_NONE,eCSSUnit_Enumerated);break;}// look for more keywordsnsCSSValuekeyword;int32_tindex;for(index=0;index<3;index++){if(!ParseEnum(keyword,kTextDecorationKTable)){break;}int32_tnewValue=keyword.GetIntValue();if(newValue==eDecorationNone||newValue&intValue){// 'none' keyword in conjuction with others is not allowed, and// duplicate keyword is not allowed.returnfalse;}intValue|=newValue;}blink.SetIntValue((intValue&eDecorationBlink)!=0?NS_STYLE_TEXT_BLINK_BLINK:NS_STYLE_TEXT_BLINK_NONE,eCSSUnit_Enumerated);line.SetIntValue((intValue&~eDecorationBlink),eCSSUnit_Enumerated);break;}default:blink=line=color=style=value;break;}AppendValue(eCSSProperty_text_blink,blink);AppendValue(eCSSProperty_text_decoration_line,line);AppendValue(eCSSProperty_text_decoration_color,color);AppendValue(eCSSProperty_text_decoration_style,style);returntrue;}boolCSSParserImpl::ParseTextDecorationLine(nsCSSValue&aValue){if(ParseVariant(aValue,VARIANT_HK,nsCSSProps::kTextDecorationLineKTable)){if(eCSSUnit_Enumerated==aValue.GetUnit()){int32_tintValue=aValue.GetIntValue();if(intValue!=NS_STYLE_TEXT_DECORATION_LINE_NONE){// look for more keywordsnsCSSValuekeyword;int32_tindex;for(index=0;index<2;index++){if(ParseEnum(keyword,nsCSSProps::kTextDecorationLineKTable)){int32_tnewValue=keyword.GetIntValue();if(newValue==NS_STYLE_TEXT_DECORATION_LINE_NONE||newValue&intValue){// 'none' keyword in conjuction with others is not allowed, and// duplicate keyword is not allowed.returnfalse;}intValue|=newValue;}else{break;}}aValue.SetIntValue(intValue,eCSSUnit_Enumerated);}}returntrue;}returnfalse;}boolCSSParserImpl::ParseTextOverflow(nsCSSValue&aValue){if(ParseVariant(aValue,VARIANT_INHERIT,nullptr)){// 'inherit' and 'initial' must be alonereturntrue;}nsCSSValueleft;if(!ParseVariant(left,VARIANT_KEYWORD|VARIANT_STRING,nsCSSProps::kTextOverflowKTable))returnfalse;nsCSSValueright;if(ParseVariant(right,VARIANT_KEYWORD|VARIANT_STRING,nsCSSProps::kTextOverflowKTable))aValue.SetPairValue(left,right);else{aValue=left;}returntrue;}///////////////////////////////////////////////////////// transform Parsing Implementation/* Reads a function list of arguments. Do not call this function * directly; it's mean to be caled from ParseFunction. */boolCSSParserImpl::ParseFunctionInternals(constint32_taVariantMask[],uint16_taMinElems,uint16_taMaxElems,InfallibleTArray<nsCSSValue>&aOutput){for(uint16_tindex=0;index<aMaxElems;++index){nsCSSValuenewValue;if(!ParseVariant(newValue,aVariantMask[index],nullptr))returnfalse;aOutput.AppendElement(newValue);// See whether to continue or whether to look for end of function.if(!ExpectSymbol(',',true)){// We need to read the closing parenthesis, and also must take care// that we haven't read too few symbols.returnExpectSymbol(')',true)&&(index+1)>=aMinElems;}}// If we're here, we finished looping without hitting the end, so we read too// many elements.returnfalse;}/* Parses a function [ input of the form (a [, b]*) ] and stores it * as an nsCSSValue that holds a function of the form * function-name arg1 arg2 ... argN * * On error, the return value is false. * * @param aFunction The name of the function that we're reading. * @param aAllowedTypes An array of values corresponding to the legal * types for each element in the function. The zeroth element in the * array corresponds to the first function parameter, etc. The length * of this array _must_ be greater than or equal to aMaxElems or the * behavior is undefined. * @param aMinElems Minimum number of elements to read. Reading fewer than * this many elements will result in the function failing. * @param aMaxElems Maximum number of elements to read. Reading more than * this many elements will result in the function failing. * @param aValue (out) The value that was parsed. */boolCSSParserImpl::ParseFunction(constnsString&aFunction,constint32_taAllowedTypes[],uint16_taMinElems,uint16_taMaxElems,nsCSSValue&aValue){typedefInfallibleTArray<nsCSSValue>::size_typearrlen_t;/* 2^16 - 2, so that if we have 2^16 - 2 transforms, we have 2^16 - 1 * elements stored in the the nsCSSValue::Array. */staticconstarrlen_tMAX_ALLOWED_ELEMS=0xFFFE;/* Make a copy of the function name, since the reference is _probably_ to * mToken.mIdent, which is going to get overwritten during the course of this * function. */nsStringfunctionName(aFunction);/* Read in a list of values as an array, failing if we can't or if * it's out of bounds. */InfallibleTArray<nsCSSValue>foundValues;if(!ParseFunctionInternals(aAllowedTypes,aMinElems,aMaxElems,foundValues))returnfalse;/* Now, convert this array into an nsCSSValue::Array object. * We'll need N + 1 spots, one for the function name and the rest for the * arguments. In case the user has given us more than 2^16 - 2 arguments, * we'll truncate them at 2^16 - 2 arguments. */uint16_tnumElements=(foundValues.Length()<=MAX_ALLOWED_ELEMS?foundValues.Length()+1:MAX_ALLOWED_ELEMS);nsRefPtr<nsCSSValue::Array>convertedArray=nsCSSValue::Array::Create(numElements);/* Copy things over. */convertedArray->Item(0).SetStringValue(functionName,eCSSUnit_Ident);for(uint16_tindex=0;index+1<numElements;++index)convertedArray->Item(index+1)=foundValues[static_cast<arrlen_t>(index)];/* Fill in the outparam value with the array. */aValue.SetArrayValue(convertedArray,eCSSUnit_Function);/* Return it! */returntrue;}/** * Given a token, determines the minimum and maximum number of function * parameters to read, along with the mask that should be used to read * those function parameters. If the token isn't a transform function, * returns an error. * * @param aToken The token identifying the function. * @param aMinElems [out] The minimum number of elements to read. * @param aMaxElems [out] The maximum number of elements to read * @param aVariantMask [out] The variant mask to use during parsing * @return Whether the information was loaded successfully. */staticboolGetFunctionParseInformation(nsCSSKeywordaToken,boolaIsPrefixed,uint16_t&aMinElems,uint16_t&aMaxElems,constint32_t*&aVariantMask,bool&aIs3D){/* These types represent the common variant masks that will be used to * parse out the individual functions. The order in the enumeration * must match the order in which the masks are declared. */enum{eLengthPercentCalc,eLengthCalc,eTwoLengthPercentCalcs,eTwoLengthPercentCalcsOneLengthCalc,eAngle,eTwoAngles,eNumber,ePositiveLength,eTwoNumbers,eThreeNumbers,eThreeNumbersOneAngle,eMatrix,eMatrixPrefixed,eMatrix3d,eMatrix3dPrefixed,eNumVariantMasks};staticconstint32_tkMaxElemsPerFunction=16;staticconstint32_tkVariantMasks[eNumVariantMasks][kMaxElemsPerFunction]={{VARIANT_LPCALC},{VARIANT_LENGTH|VARIANT_CALC},{VARIANT_LPCALC,VARIANT_LPCALC},{VARIANT_LPCALC,VARIANT_LPCALC,VARIANT_LENGTH|VARIANT_CALC},{VARIANT_ANGLE_OR_ZERO},{VARIANT_ANGLE_OR_ZERO,VARIANT_ANGLE_OR_ZERO},{VARIANT_NUMBER},{VARIANT_LENGTH|VARIANT_POSITIVE_DIMENSION},{VARIANT_NUMBER,VARIANT_NUMBER},{VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER},{VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_ANGLE_OR_ZERO},{VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER},{VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_LPNCALC,VARIANT_LPNCALC},{VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER},{VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_NUMBER,VARIANT_LPNCALC,VARIANT_LPNCALC,VARIANT_LNCALC,VARIANT_NUMBER}};#ifdef DEBUGstaticconstuint8_tkVariantMaskLengths[eNumVariantMasks]={1,1,2,3,1,2,1,1,2,3,4,6,6,16,16};#endifint32_tvariantIndex=eNumVariantMasks;aIs3D=false;switch(aToken){caseeCSSKeyword_translatex:caseeCSSKeyword_translatey:/* Exactly one length or percent. */variantIndex=eLengthPercentCalc;aMinElems=1U;aMaxElems=1U;break;caseeCSSKeyword_translatez:/* Exactly one length */variantIndex=eLengthCalc;aMinElems=1U;aMaxElems=1U;aIs3D=true;break;caseeCSSKeyword_translate3d:/* Exactly two lengthds or percents and a number */variantIndex=eTwoLengthPercentCalcsOneLengthCalc;aMinElems=3U;aMaxElems=3U;aIs3D=true;break;caseeCSSKeyword_scalez:aIs3D=true;caseeCSSKeyword_scalex:caseeCSSKeyword_scaley:/* Exactly one scale factor. */variantIndex=eNumber;aMinElems=1U;aMaxElems=1U;break;caseeCSSKeyword_scale3d:/* Exactly three scale factors. */variantIndex=eThreeNumbers;aMinElems=3U;aMaxElems=3U;aIs3D=true;break;caseeCSSKeyword_rotatex:caseeCSSKeyword_rotatey:aIs3D=true;caseeCSSKeyword_rotate:caseeCSSKeyword_rotatez:/* Exactly one angle. */variantIndex=eAngle;aMinElems=1U;aMaxElems=1U;break;caseeCSSKeyword_rotate3d:variantIndex=eThreeNumbersOneAngle;aMinElems=4U;aMaxElems=4U;aIs3D=true;break;caseeCSSKeyword_translate:/* One or two lengths or percents. */variantIndex=eTwoLengthPercentCalcs;aMinElems=1U;aMaxElems=2U;break;caseeCSSKeyword_skew:/* Exactly one or two angles. */variantIndex=eTwoAngles;aMinElems=1U;aMaxElems=2U;break;caseeCSSKeyword_scale:/* One or two scale factors. */variantIndex=eTwoNumbers;aMinElems=1U;aMaxElems=2U;break;caseeCSSKeyword_skewx:/* Exactly one angle. */variantIndex=eAngle;aMinElems=1U;aMaxElems=1U;break;caseeCSSKeyword_skewy:/* Exactly one angle. */variantIndex=eAngle;aMinElems=1U;aMaxElems=1U;break;caseeCSSKeyword_matrix:/* Six values, all numbers. */variantIndex=aIsPrefixed?eMatrixPrefixed:eMatrix;aMinElems=6U;aMaxElems=6U;break;caseeCSSKeyword_matrix3d:/* 16 matrix values, all numbers */variantIndex=aIsPrefixed?eMatrix3dPrefixed:eMatrix3d;aMinElems=16U;aMaxElems=16U;aIs3D=true;break;caseeCSSKeyword_perspective:/* Exactly one scale number. */variantIndex=ePositiveLength;aMinElems=1U;aMaxElems=1U;aIs3D=true;break;default:/* Oh dear, we didn't match. Report an error. */returnfalse;}NS_ASSERTION(aMinElems>0,"Didn't update minimum elements!");NS_ASSERTION(aMaxElems>0,"Didn't update maximum elements!");NS_ASSERTION(aMinElems<=aMaxElems,"aMinElems > aMaxElems!");NS_ASSERTION(variantIndex>=0,"Invalid variant mask!");NS_ASSERTION(variantIndex<eNumVariantMasks,"Invalid variant mask!");#ifdef DEBUGNS_ASSERTION(aMaxElems<=kVariantMaskLengths[variantIndex],"Invalid aMaxElems for this variant mask.");#endif// Convert the index into a mask.aVariantMask=kVariantMasks[variantIndex];returntrue;}/* Reads a single transform function from the tokenizer stream, reporting an * error if something goes wrong. */boolCSSParserImpl::ParseSingleTransform(boolaIsPrefixed,nsCSSValue&aValue,bool&aIs3D){if(!GetToken(true))returnfalse;if(mToken.mType!=eCSSToken_Function){UngetToken();returnfalse;}constint32_t*variantMask;uint16_tminElems,maxElems;nsCSSKeywordkeyword=nsCSSKeywords::LookupKeyword(mToken.mIdent);if(!GetFunctionParseInformation(keyword,aIsPrefixed,minElems,maxElems,variantMask,aIs3D))returnfalse;// Bug 721136: Normalize the identifier to lowercase, except that things// like scaleX should have the last character capitalized. This matches// what other browsers do.nsContentUtils::ASCIIToLower(mToken.mIdent);switch(keyword){caseeCSSKeyword_rotatex:caseeCSSKeyword_scalex:caseeCSSKeyword_skewx:caseeCSSKeyword_translatex:mToken.mIdent.Replace(mToken.mIdent.Length()-1,1,PRUnichar('X'));break;caseeCSSKeyword_rotatey:caseeCSSKeyword_scaley:caseeCSSKeyword_skewy:caseeCSSKeyword_translatey:mToken.mIdent.Replace(mToken.mIdent.Length()-1,1,PRUnichar('Y'));break;caseeCSSKeyword_rotatez:caseeCSSKeyword_scalez:caseeCSSKeyword_translatez:mToken.mIdent.Replace(mToken.mIdent.Length()-1,1,PRUnichar('Z'));break;default:break;}returnParseFunction(mToken.mIdent,variantMask,minElems,maxElems,aValue);}/* Parses a transform property list by continuously reading in properties * and constructing a matrix from it. */boolCSSParserImpl::ParseTransform(boolaIsPrefixed){nsCSSValuevalue;if(ParseVariant(value,VARIANT_INHERIT|VARIANT_NONE,nullptr)){// 'inherit', 'initial', and 'none' must be aloneif(!ExpectEndProperty()){returnfalse;}}else{nsCSSValueList*cur=value.SetListValue();for(;;){boolis3D;if(!ParseSingleTransform(aIsPrefixed,cur->mValue,is3D)){returnfalse;}if(is3D&&!nsLayoutUtils::Are3DTransformsEnabled()){returnfalse;}if(CheckEndProperty()){break;}cur->mNext=newnsCSSValueList;cur=cur->mNext;}}AppendValue(eCSSProperty_transform,value);returntrue;}boolCSSParserImpl::ParseTransformOrigin(boolaPerspective){nsCSSValuePairposition;if(!ParseBoxPositionValues(position,true))returnfalse;nsCSSPropertyprop=eCSSProperty_transform_origin;if(aPerspective){if(!ExpectEndProperty()){returnfalse;}prop=eCSSProperty_perspective_origin;}// Unlike many other uses of pairs, this position should always be stored// as a pair, even if the values are the same, so it always serializes as// a pair, and to keep the computation code simple.if(position.mXValue.GetUnit()==eCSSUnit_Inherit||position.mXValue.GetUnit()==eCSSUnit_Initial){NS_ABORT_IF_FALSE(position.mXValue==position.mYValue,"inherit/initial only half?");AppendValue(prop,position.mXValue);}else{nsCSSValuevalue;if(aPerspective){value.SetPairValue(position.mXValue,position.mYValue);}else{nsCSSValuedepth;if(!nsLayoutUtils::Are3DTransformsEnabled()||// only try parsing if 3-D transforms are enabled!ParseVariant(depth,VARIANT_LENGTH|VARIANT_CALC,nullptr)){depth.SetFloatValue(0.0f,eCSSUnit_Pixel);}value.SetTripletValue(position.mXValue,position.mYValue,depth);}AppendValue(prop,value);}returntrue;}boolCSSParserImpl::ParseTransitionProperty(){nsCSSValuevalue;if(ParseVariant(value,VARIANT_INHERIT|VARIANT_NONE,nullptr)){// 'inherit', 'initial', and 'none' must be aloneif(!ExpectEndProperty()){returnfalse;}}else{// Accept a list of arbitrary identifiers. They should be// CSS properties, but we want to accept any so that we// accept properties that we don't know about yet, e.g.// transition-property: invalid-property, left, opacity;nsCSSValueList*cur=value.SetListValue();for(;;){if(!ParseVariant(cur->mValue,VARIANT_IDENTIFIER|VARIANT_ALL,nullptr)){returnfalse;}if(cur->mValue.GetUnit()==eCSSUnit_Ident){nsDependentStringstr(cur->mValue.GetStringBufferValue());// Exclude 'none' and 'inherit' and 'initial' according to the// same rules as for 'counter-reset' in CSS 2.1.if(str.LowerCaseEqualsLiteral("none")||str.LowerCaseEqualsLiteral("inherit")||str.LowerCaseEqualsLiteral("initial")){returnfalse;}}if(CheckEndProperty()){break;}if(!ExpectSymbol(',',true)){REPORT_UNEXPECTED_TOKEN(PEExpectedComma);returnfalse;}cur->mNext=newnsCSSValueList;cur=cur->mNext;}}AppendValue(eCSSProperty_transition_property,value);returntrue;}boolCSSParserImpl::ParseTransitionTimingFunctionValues(nsCSSValue&aValue){NS_ASSERTION(!mHavePushBack&&mToken.mType==eCSSToken_Function&&mToken.mIdent.LowerCaseEqualsLiteral("cubic-bezier"),"unexpected initial state");nsRefPtr<nsCSSValue::Array>val=nsCSSValue::Array::Create(4);floatx1,x2,y1,y2;if(!ParseTransitionTimingFunctionValueComponent(x1,',',true)||!ParseTransitionTimingFunctionValueComponent(y1,',',false)||!ParseTransitionTimingFunctionValueComponent(x2,',',true)||!ParseTransitionTimingFunctionValueComponent(y2,')',false)){returnfalse;}val->Item(0).SetFloatValue(x1,eCSSUnit_Number);val->Item(1).SetFloatValue(y1,eCSSUnit_Number);val->Item(2).SetFloatValue(x2,eCSSUnit_Number);val->Item(3).SetFloatValue(y2,eCSSUnit_Number);aValue.SetArrayValue(val,eCSSUnit_Cubic_Bezier);returntrue;}boolCSSParserImpl::ParseTransitionTimingFunctionValueComponent(float&aComponent,charaStop,boolaCheckRange){if(!GetToken(true)){returnfalse;}nsCSSToken*tk=&mToken;if(tk->mType==eCSSToken_Number){floatnum=tk->mNumber;if(aCheckRange&&(num<0.0||num>1.0)){returnfalse;}aComponent=num;if(ExpectSymbol(aStop,true)){returntrue;}}returnfalse;}boolCSSParserImpl::ParseTransitionStepTimingFunctionValues(nsCSSValue&aValue){NS_ASSERTION(!mHavePushBack&&mToken.mType==eCSSToken_Function&&mToken.mIdent.LowerCaseEqualsLiteral("steps"),"unexpected initial state");nsRefPtr<nsCSSValue::Array>val=nsCSSValue::Array::Create(2);if(!ParseOneOrLargerVariant(val->Item(0),VARIANT_INTEGER,nullptr)){returnfalse;}int32_ttype=NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END;if(ExpectSymbol(',',true)){if(!GetToken(true)){returnfalse;}type=-1;if(mToken.mType==eCSSToken_Ident){if(mToken.mIdent.LowerCaseEqualsLiteral("start")){type=NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START;}elseif(mToken.mIdent.LowerCaseEqualsLiteral("end")){type=NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END;}}if(type==-1){UngetToken();returnfalse;}}val->Item(1).SetIntValue(type,eCSSUnit_Enumerated);if(!ExpectSymbol(')',true)){returnfalse;}aValue.SetArrayValue(val,eCSSUnit_Steps);returntrue;}staticnsCSSValueList*AppendValueToList(nsCSSValue&aContainer,nsCSSValueList*aTail,constnsCSSValue&aValue){nsCSSValueList*entry;if(aContainer.GetUnit()==eCSSUnit_Null){NS_ABORT_IF_FALSE(!aTail,"should not have an entry");entry=aContainer.SetListValue();}else{NS_ABORT_IF_FALSE(!aTail->mNext,"should not have a next entry");NS_ABORT_IF_FALSE(aContainer.GetUnit()==eCSSUnit_List,"not a list");entry=newnsCSSValueList;aTail->mNext=entry;}entry->mValue=aValue;returnentry;}CSSParserImpl::ParseAnimationOrTransitionShorthandResultCSSParserImpl::ParseAnimationOrTransitionShorthand(constnsCSSProperty*aProperties,constnsCSSValue*aInitialValues,nsCSSValue*aValues,size_taNumProperties){nsCSSValuetempValue;// first see if 'inherit' or 'initial' is specified. If one is,// it can be the only thing specified, so don't attempt to parse any// additional propertiesif(ParseVariant(tempValue,VARIANT_INHERIT,nullptr)){for(uint32_ti=0;i<aNumProperties;++i){AppendValue(aProperties[i],tempValue);}returneParseAnimationOrTransitionShorthand_Inherit;}staticconstsize_tmaxNumProperties=7;NS_ABORT_IF_FALSE(aNumProperties<=maxNumProperties,"can't handle this many properties");nsCSSValueList*cur[maxNumProperties];boolparsedProperty[maxNumProperties];for(size_ti=0;i<aNumProperties;++i){cur[i]=nullptr;}boolatEOP=false;// at end of property?for(;;){// loop over comma-separated transitions or animations// whether a particular subproperty was specified for this// transition or animationfor(size_ti=0;i<aNumProperties;++i){parsedProperty[i]=false;}for(;;){// loop over values within a transition or animationboolfoundProperty=false;// check to see if we're at the end of one full transition or// animation definition (either because we hit a comma or because// we hit the end of the property definition)if(ExpectSymbol(',',true))break;if(CheckEndProperty()){atEOP=true;break;}// else, try to parse the next transition or animation sub-propertyfor(uint32_ti=0;!foundProperty&&i<aNumProperties;++i){if(!parsedProperty[i]){// if we haven't found this property yet, try to parse itif(ParseSingleValueProperty(tempValue,aProperties[i])){parsedProperty[i]=true;cur[i]=AppendValueToList(aValues[i],cur[i],tempValue);foundProperty=true;break;// out of inner loop; continue looking for next sub-property}}}if(!foundProperty){// We're not at a ',' or at the end of the property, but we couldn't// parse any of the sub-properties, so the declaration is invalid.returneParseAnimationOrTransitionShorthand_Error;}}// We hit the end of the property or the end of one transition// or animation definition, add its components to the list.for(uint32_ti=0;i<aNumProperties;++i){// If all of the subproperties were not explicitly specified, fill// in the missing ones with initial values.if(!parsedProperty[i]){cur[i]=AppendValueToList(aValues[i],cur[i],aInitialValues[i]);}}if(atEOP)break;// else we just hit a ',' so continue parsing the next compound transition}returneParseAnimationOrTransitionShorthand_Values;}boolCSSParserImpl::ParseTransition(){staticconstnsCSSPropertykTransitionProperties[]={eCSSProperty_transition_duration,eCSSProperty_transition_timing_function,// Must check 'transition-delay' after 'transition-duration', since// that's our assumption about what the spec means for the shorthand// syntax (the first time given is the duration, and the second// given is the delay).eCSSProperty_transition_delay,// Must check 'transition-property' after// 'transition-timing-function' since 'transition-property' accepts// any keyword.eCSSProperty_transition_property};staticconstuint32_tnumProps=NS_ARRAY_LENGTH(kTransitionProperties);// this is a shorthand property that accepts -property, -delay,// -duration, and -timing-function with some components missing.// there can be multiple transitions, separated with commasnsCSSValueinitialValues[numProps];initialValues[0].SetFloatValue(0.0,eCSSUnit_Seconds);initialValues[1].SetIntValue(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE,eCSSUnit_Enumerated);initialValues[2].SetFloatValue(0.0,eCSSUnit_Seconds);initialValues[3].SetAllValue();nsCSSValuevalues[numProps];ParseAnimationOrTransitionShorthandResultspres=ParseAnimationOrTransitionShorthand(kTransitionProperties,initialValues,values,numProps);if(spres!=eParseAnimationOrTransitionShorthand_Values){returnspres!=eParseAnimationOrTransitionShorthand_Error;}// Make two checks on the list for 'transition-property':// + If there is more than one item, then none of the items can be// 'none' or 'all'.// + None of the items can be 'inherit' or 'initial' (this is the case,// like with counter-reset &c., where CSS 2.1 specifies 'initial', so// we should check it without the -moz- prefix).{NS_ABORT_IF_FALSE(kTransitionProperties[3]==eCSSProperty_transition_property,"array index mismatch");nsCSSValueList*l=values[3].GetListValue();boolmultipleItems=!!l->mNext;do{constnsCSSValue&val=l->mValue;if(val.GetUnit()==eCSSUnit_None){if(multipleItems){// This is a syntax error.returnfalse;}// Unbox a solitary 'none'.values[3].SetNoneValue();break;}if(val.GetUnit()==eCSSUnit_Ident){nsDependentStringstr(val.GetStringBufferValue());if(str.EqualsLiteral("inherit")||str.EqualsLiteral("initial")){returnfalse;}}}while((l=l->mNext));}// Save all parsed transition sub-properties in mTempDatafor(uint32_ti=0;i<numProps;++i){AppendValue(kTransitionProperties[i],values[i]);}returntrue;}boolCSSParserImpl::ParseAnimation(){staticconstnsCSSPropertykAnimationProperties[]={eCSSProperty_animation_duration,eCSSProperty_animation_timing_function,// Must check 'animation-delay' after 'animation-duration', since// that's our assumption about what the spec means for the shorthand// syntax (the first time given is the duration, and the second// given is the delay).eCSSProperty_animation_delay,eCSSProperty_animation_direction,eCSSProperty_animation_fill_mode,eCSSProperty_animation_iteration_count,// Must check 'animation-name' after 'animation-timing-function',// 'animation-direction', 'animation-fill-mode',// 'animation-iteration-count', and 'animation-play-state' since// 'animation-name' accepts any keyword.eCSSProperty_animation_name};staticconstuint32_tnumProps=NS_ARRAY_LENGTH(kAnimationProperties);// this is a shorthand property that accepts -property, -delay,// -duration, and -timing-function with some components missing.// there can be multiple animations, separated with commasnsCSSValueinitialValues[numProps];initialValues[0].SetFloatValue(0.0,eCSSUnit_Seconds);initialValues[1].SetIntValue(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE,eCSSUnit_Enumerated);initialValues[2].SetFloatValue(0.0,eCSSUnit_Seconds);initialValues[3].SetIntValue(NS_STYLE_ANIMATION_DIRECTION_NORMAL,eCSSUnit_Enumerated);initialValues[4].SetIntValue(NS_STYLE_ANIMATION_FILL_MODE_NONE,eCSSUnit_Enumerated);initialValues[5].SetFloatValue(1.0f,eCSSUnit_Number);initialValues[6].SetNoneValue();nsCSSValuevalues[numProps];ParseAnimationOrTransitionShorthandResultspres=ParseAnimationOrTransitionShorthand(kAnimationProperties,initialValues,values,numProps);if(spres!=eParseAnimationOrTransitionShorthand_Values){returnspres!=eParseAnimationOrTransitionShorthand_Error;}// Save all parsed animation sub-properties in mTempDatafor(uint32_ti=0;i<numProps;++i){AppendValue(kAnimationProperties[i],values[i]);}returntrue;}boolCSSParserImpl::ParseShadowItem(nsCSSValue&aValue,boolaIsBoxShadow){// A shadow list item is an array, with entries in this sequence:enum{IndexX,IndexY,IndexRadius,IndexSpread,// only for box-shadowIndexColor,IndexInset// only for box-shadow};nsRefPtr<nsCSSValue::Array>val=nsCSSValue::Array::Create(6);if(aIsBoxShadow){// Optional inset keyword (ignore errors)ParseVariant(val->Item(IndexInset),VARIANT_KEYWORD,nsCSSProps::kBoxShadowTypeKTable);}nsCSSValuexOrColor;boolhaveColor=false;if(!ParseVariant(xOrColor,VARIANT_COLOR|VARIANT_LENGTH|VARIANT_CALC,nullptr)){returnfalse;}if(xOrColor.IsLengthUnit()||xOrColor.IsCalcUnit()){val->Item(IndexX)=xOrColor;}else{// Must be a color (as string or color value)NS_ASSERTION(xOrColor.GetUnit()==eCSSUnit_Ident||xOrColor.GetUnit()==eCSSUnit_Color||xOrColor.GetUnit()==eCSSUnit_EnumColor,"Must be a color value");val->Item(IndexColor)=xOrColor;haveColor=true;// X coordinate mandatory after colorif(!ParseVariant(val->Item(IndexX),VARIANT_LENGTH|VARIANT_CALC,nullptr)){returnfalse;}}// Y coordinate; mandatoryif(!ParseVariant(val->Item(IndexY),VARIANT_LENGTH|VARIANT_CALC,nullptr)){returnfalse;}// Optional radius. Ignore errors except if they pass a negative// value which we must reject. If we use ParseNonNegativeVariant// we can't tell the difference between an unspecified radius// and a negative radius.if(ParseVariant(val->Item(IndexRadius),VARIANT_LENGTH|VARIANT_CALC,nullptr)&&val->Item(IndexRadius).IsLengthUnit()&&val->Item(IndexRadius).GetFloatValue()<0){returnfalse;}if(aIsBoxShadow){// Optional spreadParseVariant(val->Item(IndexSpread),VARIANT_LENGTH|VARIANT_CALC,nullptr);}if(!haveColor){// Optional colorParseVariant(val->Item(IndexColor),VARIANT_COLOR,nullptr);}if(aIsBoxShadow&&val->Item(IndexInset).GetUnit()==eCSSUnit_Null){// Optional inset keywordParseVariant(val->Item(IndexInset),VARIANT_KEYWORD,nsCSSProps::kBoxShadowTypeKTable);}aValue.SetArrayValue(val,eCSSUnit_Array);returntrue;}boolCSSParserImpl::ParseShadowList(nsCSSPropertyaProperty){nsAutoParseCompoundPropertycompound(this);boolisBoxShadow=aProperty==eCSSProperty_box_shadow;nsCSSValuevalue;if(ParseVariant(value,VARIANT_INHERIT|VARIANT_NONE,nullptr)){// 'inherit', 'initial', and 'none' must be aloneif(!ExpectEndProperty()){returnfalse;}}else{nsCSSValueList*cur=value.SetListValue();for(;;){if(!ParseShadowItem(cur->mValue,isBoxShadow)){returnfalse;}if(CheckEndProperty()){break;}if(!ExpectSymbol(',',true)){returnfalse;}cur->mNext=newnsCSSValueList;cur=cur->mNext;}}AppendValue(aProperty,value);returntrue;}int32_tCSSParserImpl::GetNamespaceIdForPrefix(constnsString&aPrefix){NS_PRECONDITION(!aPrefix.IsEmpty(),"Must have a prefix here");int32_tnameSpaceID=kNameSpaceID_Unknown;if(mNameSpaceMap){// user-specified identifiers are case-sensitive (bug 416106)nsCOMPtr<nsIAtom>prefix=do_GetAtom(aPrefix);if(!prefix){NS_RUNTIMEABORT("do_GetAtom failed - out of memory?");}nameSpaceID=mNameSpaceMap->FindNameSpaceID(prefix);}// else no declared namespacesif(nameSpaceID==kNameSpaceID_Unknown){// unknown prefix, dump itREPORT_UNEXPECTED_P(PEUnknownNamespacePrefix,aPrefix);}returnnameSpaceID;}voidCSSParserImpl::SetDefaultNamespaceOnSelector(nsCSSSelector&aSelector){if(mNameSpaceMap){aSelector.SetNameSpace(mNameSpaceMap->FindNameSpaceID(nullptr));}else{aSelector.SetNameSpace(kNameSpaceID_Unknown);// wildcard}}boolCSSParserImpl::ParsePaint(nsCSSPropertyaPropID){nsCSSValuex,y;if(!ParseVariant(x,VARIANT_HCK|VARIANT_NONE|VARIANT_URL,nsCSSProps::kObjectPatternKTable)){returnfalse;}boolcanHaveFallback=x.GetUnit()==eCSSUnit_URL||x.GetUnit()==eCSSUnit_Enumerated;if(canHaveFallback){if(!ParseVariant(y,VARIANT_COLOR|VARIANT_NONE,nullptr))y.SetNoneValue();}if(!ExpectEndProperty())returnfalse;if(!canHaveFallback){AppendValue(aPropID,x);}else{nsCSSValueval;val.SetPairValue(x,y);AppendValue(aPropID,val);}returntrue;}boolCSSParserImpl::ParseDasharray(){nsCSSValuevalue;if(ParseVariant(value,VARIANT_HK|VARIANT_NONE,nsCSSProps::kStrokeObjectValueKTable)){// 'inherit', 'initial', and 'none' are only allowed on their ownif(!ExpectEndProperty()){returnfalse;}}else{nsCSSValueList*cur=value.SetListValue();for(;;){if(!ParseNonNegativeVariant(cur->mValue,VARIANT_LPN,nullptr)){returnfalse;}if(CheckEndProperty()){break;}// skip optional commas between elements(void)ExpectSymbol(',',true);cur->mNext=newnsCSSValueList;cur=cur->mNext;}}AppendValue(eCSSProperty_stroke_dasharray,value);returntrue;}boolCSSParserImpl::ParseMarker(){nsCSSValuemarker;if(ParseSingleValueProperty(marker,eCSSProperty_marker_end)){if(ExpectEndProperty()){AppendValue(eCSSProperty_marker_end,marker);AppendValue(eCSSProperty_marker_mid,marker);AppendValue(eCSSProperty_marker_start,marker);returntrue;}}returnfalse;}boolCSSParserImpl::ParsePaintOrder(){MOZ_STATIC_ASSERT((1<<NS_STYLE_PAINT_ORDER_BITWIDTH)>NS_STYLE_PAINT_ORDER_LAST_VALUE,"bitfield width insufficient for paint-order constants");staticconstint32_tkPaintOrderKTable[]={eCSSKeyword_normal,NS_STYLE_PAINT_ORDER_NORMAL,eCSSKeyword_fill,NS_STYLE_PAINT_ORDER_FILL,eCSSKeyword_stroke,NS_STYLE_PAINT_ORDER_STROKE,eCSSKeyword_markers,NS_STYLE_PAINT_ORDER_MARKERS,eCSSKeyword_UNKNOWN,-1};MOZ_STATIC_ASSERT(NS_ARRAY_LENGTH(kPaintOrderKTable)==2*(NS_STYLE_PAINT_ORDER_LAST_VALUE+2),"missing paint-order values in kPaintOrderKTable");nsCSSValuevalue;if(!ParseVariant(value,VARIANT_HK,kPaintOrderKTable)){returnfalse;}uint32_tseen=0;uint32_torder=0;uint32_tposition=0;// Ensure that even cast to a signed int32_t when stored in CSSValue,// we have enough space for the entire paint-order value.MOZ_STATIC_ASSERT(NS_STYLE_PAINT_ORDER_BITWIDTH*NS_STYLE_PAINT_ORDER_LAST_VALUE<32,"seen and order not big enough");if(value.GetUnit()==eCSSUnit_Enumerated){uint32_tcomponent=static_cast<uint32_t>(value.GetIntValue());if(component!=NS_STYLE_PAINT_ORDER_NORMAL){boolparsedOK=true;for(;;){if(seen&(1<<component)){// Already seen this component.UngetToken();parsedOK=false;break;}seen|=(1<<component);order|=(component<<position);position+=NS_STYLE_PAINT_ORDER_BITWIDTH;if(!ParseEnum(value,kPaintOrderKTable)){break;}component=value.GetIntValue();if(component==NS_STYLE_PAINT_ORDER_NORMAL){// Can't have "normal" in the middle of the list of paint components.UngetToken();parsedOK=false;break;}}// Fill in the remaining paint-order components in the order of their// constant values.if(parsedOK){for(component=1;component<=NS_STYLE_PAINT_ORDER_LAST_VALUE;component++){if(!(seen&(1<<component))){order|=(component<<position);position+=NS_STYLE_PAINT_ORDER_BITWIDTH;}}}}MOZ_STATIC_ASSERT(NS_STYLE_PAINT_ORDER_NORMAL==0,"unexpected value for NS_STYLE_PAINT_ORDER_NORMAL");value.SetIntValue(static_cast<int32_t>(order),eCSSUnit_Enumerated);}if(!ExpectEndProperty()){returnfalse;}AppendValue(eCSSProperty_paint_order,value);returntrue;}}// anonymous namespace// Recycling of parser implementation objectsstaticCSSParserImpl*gFreeList=nullptr;nsCSSParser::nsCSSParser(mozilla::css::Loader*aLoader,nsCSSStyleSheet*aSheet){CSSParserImpl*impl=gFreeList;if(impl){gFreeList=impl->mNextFree;impl->mNextFree=nullptr;}else{impl=newCSSParserImpl();}if(aLoader){impl->SetChildLoader(aLoader);impl->SetQuirkMode(aLoader->GetCompatibilityMode()==eCompatibility_NavQuirks);}if(aSheet){impl->SetStyleSheet(aSheet);}mImpl=static_cast<void*>(impl);}nsCSSParser::~nsCSSParser(){CSSParserImpl*impl=static_cast<CSSParserImpl*>(mImpl);impl->Reset();impl->mNextFree=gFreeList;gFreeList=impl;}/* static */voidnsCSSParser::Shutdown(){CSSParserImpl*tofree=gFreeList;CSSParserImpl*next;while(tofree){next=tofree->mNextFree;deletetofree;tofree=next;}}// Wrapper methodsnsresultnsCSSParser::SetStyleSheet(nsCSSStyleSheet*aSheet){returnstatic_cast<CSSParserImpl*>(mImpl)->SetStyleSheet(aSheet);}nsresultnsCSSParser::SetQuirkMode(boolaQuirkMode){returnstatic_cast<CSSParserImpl*>(mImpl)->SetQuirkMode(aQuirkMode);}nsresultnsCSSParser::SetChildLoader(mozilla::css::Loader*aChildLoader){returnstatic_cast<CSSParserImpl*>(mImpl)->SetChildLoader(aChildLoader);}nsresultnsCSSParser::ParseSheet(constnsAString&aInput,nsIURI*aSheetURI,nsIURI*aBaseURI,nsIPrincipal*aSheetPrincipal,uint32_taLineNumber,boolaAllowUnsafeRules){returnstatic_cast<CSSParserImpl*>(mImpl)->ParseSheet(aInput,aSheetURI,aBaseURI,aSheetPrincipal,aLineNumber,aAllowUnsafeRules);}nsresultnsCSSParser::ParseStyleAttribute(constnsAString&aAttributeValue,nsIURI*aDocURI,nsIURI*aBaseURI,nsIPrincipal*aNodePrincipal,css::StyleRule**aResult){returnstatic_cast<CSSParserImpl*>(mImpl)->ParseStyleAttribute(aAttributeValue,aDocURI,aBaseURI,aNodePrincipal,aResult);}nsresultnsCSSParser::ParseDeclarations(constnsAString&aBuffer,nsIURI*aSheetURI,nsIURI*aBaseURI,nsIPrincipal*aSheetPrincipal,css::Declaration*aDeclaration,bool*aChanged){returnstatic_cast<CSSParserImpl*>(mImpl)->ParseDeclarations(aBuffer,aSheetURI,aBaseURI,aSheetPrincipal,aDeclaration,aChanged);}nsresultnsCSSParser::ParseRule(constnsAString&aRule,nsIURI*aSheetURI,nsIURI*aBaseURI,nsIPrincipal*aSheetPrincipal,css::Rule**aResult){returnstatic_cast<CSSParserImpl*>(mImpl)->ParseRule(aRule,aSheetURI,aBaseURI,aSheetPrincipal,aResult);}nsresultnsCSSParser::ParseProperty(constnsCSSPropertyaPropID,constnsAString&aPropValue,nsIURI*aSheetURI,nsIURI*aBaseURI,nsIPrincipal*aSheetPrincipal,css::Declaration*aDeclaration,bool*aChanged,boolaIsImportant,boolaIsSVGMode){returnstatic_cast<CSSParserImpl*>(mImpl)->ParseProperty(aPropID,aPropValue,aSheetURI,aBaseURI,aSheetPrincipal,aDeclaration,aChanged,aIsImportant,aIsSVGMode);}nsresultnsCSSParser::ParseMediaList(constnsSubstring&aBuffer,nsIURI*aURI,uint32_taLineNumber,nsMediaList*aMediaList,boolaHTMLMode){returnstatic_cast<CSSParserImpl*>(mImpl)->ParseMediaList(aBuffer,aURI,aLineNumber,aMediaList,aHTMLMode);}boolnsCSSParser::ParseColorString(constnsSubstring&aBuffer,nsIURI*aURI,uint32_taLineNumber,nsCSSValue&aValue){returnstatic_cast<CSSParserImpl*>(mImpl)->ParseColorString(aBuffer,aURI,aLineNumber,aValue);}nsresultnsCSSParser::ParseSelectorString(constnsSubstring&aSelectorString,nsIURI*aURI,uint32_taLineNumber,nsCSSSelectorList**aSelectorList){returnstatic_cast<CSSParserImpl*>(mImpl)->ParseSelectorString(aSelectorString,aURI,aLineNumber,aSelectorList);}already_AddRefed<nsCSSKeyframeRule>nsCSSParser::ParseKeyframeRule(constnsSubstring&aBuffer,nsIURI*aURI,uint32_taLineNumber){returnstatic_cast<CSSParserImpl*>(mImpl)->ParseKeyframeRule(aBuffer,aURI,aLineNumber);}boolnsCSSParser::ParseKeyframeSelectorString(constnsSubstring&aSelectorString,nsIURI*aURI,uint32_taLineNumber,InfallibleTArray<float>&aSelectorList){returnstatic_cast<CSSParserImpl*>(mImpl)->ParseKeyframeSelectorString(aSelectorString,aURI,aLineNumber,aSelectorList);}boolnsCSSParser::EvaluateSupportsDeclaration(constnsAString&aProperty,constnsAString&aValue,nsIURI*aDocURL,nsIURI*aBaseURL,nsIPrincipal*aDocPrincipal){returnstatic_cast<CSSParserImpl*>(mImpl)->EvaluateSupportsDeclaration(aProperty,aValue,aDocURL,aBaseURL,aDocPrincipal);}boolnsCSSParser::EvaluateSupportsCondition(constnsAString&aCondition,nsIURI*aDocURL,nsIURI*aBaseURL,nsIPrincipal*aDocPrincipal){returnstatic_cast<CSSParserImpl*>(mImpl)->EvaluateSupportsCondition(aCondition,aDocURL,aBaseURL,aDocPrincipal);}