// // Parse pseudo-classes and pseudo-elements // internal nsSelectorParsingStatus ParsePseudoSelector(ref int32_t aDataMask, nsCSSSelector aSelector, bool aIsNegated, ref string aPseudoElement, object aPseudoElementArgs, ref nsCSSPseudoElement aPseudoElementType) { Debug.Assert(!aIsNegated || (aPseudoElement == null && aPseudoElementArgs == null), "negated selectors shouldn't have a place to store pseudo elements"); if (! GetToken(false)) { // premature eof { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelEOF"); }; return nsSelectorParsingStatus.Error; } // First, find out whether we are parsing a CSS3 pseudo-element bool parsingPseudoElement = false; if (mToken.IsSymbol(':')) { parsingPseudoElement = true; if (! GetToken(false)) { // premature eof { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelEOF"); }; return nsSelectorParsingStatus.Error; } } // Do some sanity-checking on the token if (nsCSSTokenType.Ident != mToken.mType && nsCSSTokenType.Function != mToken.mType) { // malformed selector { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelBadName", mToken); }; UngetToken(); return nsSelectorParsingStatus.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 ':' string pseudo = String.Intern(":" + mToken.mIdentStr); // stash away some info about this pseudo so we only have to get it once. bool isTreePseudo = false; nsCSSPseudoElement pseudoElementType = nsCSSPseudoElements.GetPseudoType(pseudo); nsCSSPseudoClass pseudoClassType = 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 == nsCSSPseudoElement.MozPlaceholder && pseudoClassType == nsCSSPseudoClass.MozPlaceholder) { if (parsingPseudoElement) { pseudoClassType = nsCSSPseudoClass.NotPseudoClass; } else { pseudoElementType = nsCSSPseudoElement.NotPseudoElement; } } #if MOZ_XUL isTreePseudo = (pseudoElementType == nsCSSPseudoElement.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. bool isTree = (nsCSSTokenType.Function == mToken.mType) && isTreePseudo; #endif bool isPseudoElement = (pseudoElementType < nsCSSPseudoElement.PseudoElementCount); // anonymous boxes are only allowed if they're the tree boxes or we have // enabled unsafe rules bool isAnonBox = isTreePseudo || (pseudoElementType == nsCSSPseudoElement.AnonBox && mUnsafeRulesEnabled); bool isPseudoClass = (pseudoClassType != nsCSSPseudoClass.NotPseudoClass); Debug.Assert(!isPseudoClass || pseudoElementType == nsCSSPseudoElement.NotPseudoElement, "Why is this atom both a pseudo-class and a pseudo-element?"); Debug.Assert((isPseudoClass?1:0) + (isPseudoElement?1:0) + (isAnonBox?1:0) <= 1, "Shouldn't be more than one of these"); if (!isPseudoClass && !isPseudoElement && !isAnonBox) { // Not a pseudo-class, not a pseudo-element.... forget it { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelUnknown", mToken); }; UngetToken(); return nsSelectorParsingStatus.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 token if ((nsCSSTokenType.Function == mToken.mType) != ( #if MOZ_XUL isTree || #endif nsCSSPseudoClass.NotPseudo == pseudoClassType || nsCSSPseudoClasses.HasStringArg(pseudoClassType) || nsCSSPseudoClasses.HasNthPairArg(pseudoClassType) || nsCSSPseudoClasses.HasSelectorListArg(pseudoClassType))) { // There are no other function pseudos { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelNonFunc", mToken); }; UngetToken(); return nsSelectorParsingStatus.Error; } // If it starts with ".", it better be a pseudo-element if (parsingPseudoElement && !isPseudoElement && !isAnonBox) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelNotPE", mToken); }; UngetToken(); return nsSelectorParsingStatus.Error; } if (!parsingPseudoElement && nsCSSPseudoClass.NotPseudo == pseudoClassType) { if (aIsNegated) { // :not() can't be itself negated { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelDoubleNot", mToken); }; UngetToken(); return nsSelectorParsingStatus.Error; } // CSS 3 Negation pseudo-class takes one simple selector as argument nsSelectorParsingStatus parsingStatus = ParseNegatedSimpleSelector(ref aDataMask, aSelector); if (nsSelectorParsingStatus.Continue != parsingStatus) { return parsingStatus; } } else if (!parsingPseudoElement && isPseudoClass) { aDataMask |= SEL_MASK_PCLASS; if (nsCSSTokenType.Function == mToken.mType) { nsSelectorParsingStatus parsingStatus; if (nsCSSPseudoClasses.HasStringArg(pseudoClassType)) { parsingStatus = ParsePseudoClassWithIdentArg(aSelector, pseudoClassType); } else if (nsCSSPseudoClasses.HasNthPairArg(pseudoClassType)) { parsingStatus = ParsePseudoClassWithNthPairArg(aSelector, pseudoClassType); } else { Debug.Assert(nsCSSPseudoClasses.HasSelectorListArg(pseudoClassType), "unexpected pseudo with function token"); parsingStatus = ParsePseudoClassWithSelectorListArg(aSelector, pseudoClassType); } if (nsSelectorParsingStatus.Continue != parsingStatus) { if (nsSelectorParsingStatus.Error == parsingStatus) { SkipUntil(')'); } return parsingStatus; } } else { aSelector.AddPseudoClass(pseudoClassType); } } else if (isPseudoElement || isAnonBox) { // Pseudo-element. Make some more sanity checks. if (aIsNegated) { // pseudo-elements can't be negated { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelPEInNot", mToken); }; UngetToken(); return nsSelectorParsingStatus.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) #if MOZ_XUL && !isTreePseudo #endif ) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelNewStyleOnly", mToken); }; UngetToken(); return nsSelectorParsingStatus.Error; } if (0 == (aDataMask & SEL_MASK_PELEM)) { aDataMask |= SEL_MASK_PELEM; aPseudoElement = pseudo; aPseudoElementType = pseudoElementType; #if MOZ_XUL if (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)) { return nsSelectorParsingStatus.Error; } } #endif // the next *non*whitespace token must be '{' or ',' or EOF if (!GetToken(true)) { // premature eof is ok (here!) return nsSelectorParsingStatus.Done; } if ((mToken.IsSymbol('{') || mToken.IsSymbol(','))) { UngetToken(); return nsSelectorParsingStatus.Done; } { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelTrailing", mToken); }; UngetToken(); return nsSelectorParsingStatus.Error; } else { // multiple pseudo elements, not legal { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelMultiplePE", mToken); }; UngetToken(); return nsSelectorParsingStatus.Error; } } #if DEBUG else { // 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. Debug.Fail("How did this happen?"); } #endif return nsSelectorParsingStatus.Continue; }
internal void SetPseudoType(CssPseudoElement aPseudoType) { mPseudoType = aPseudoType; }
internal void SetPseudoType(CssPseudoElement aPseudoType) { mPseudoType = aPseudoType; }