internal CssSelector AddSelector(char aOperator) { var newSel = new CssSelector(); if (mSelectors != null) mSelectors.SetOperator(aOperator); newSel.mNext = mSelectors; mSelectors = newSel; return newSel; }
internal CssSelector AddSelector(char aOperator) { var newSel = new CssSelector(); if (mSelectors != null) { mSelectors.SetOperator(aOperator); } newSel.mNext = mSelectors; mSelectors = newSel; return(newSel); }
internal static IEnumerable<CssSelector> TraverseList(CssSelector @this) { return @this.TraverseList(i => i.mNext); }
// // Parse attribute selectors [attr], [attr=value], [attr|=value], // [attr~=value], [attr^=value], [attr$=value] and [attr*=value] // internal nsSelectorParsingStatus ParseAttributeSelector(ref int32_t aDataMask, nsCSSSelector aSelector) { if (! GetToken(true)) { // premature EOF { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttributeNameEOF"); }; return nsSelectorParsingStatus.Error; } int32_t nameSpaceID = nsNameSpace.None; string attr; if (mToken.IsSymbol('*')) { // wildcard namespace nameSpaceID = nsNameSpace.Unknown; if (ExpectSymbol('|', false)) { if (! GetToken(false)) { // premature EOF { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttributeNameEOF"); }; return nsSelectorParsingStatus.Error; } if (nsCSSTokenType.Ident == mToken.mType) { // attr name attr = mToken.mIdentStr; } else { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttributeNameExpected", mToken); }; UngetToken(); return nsSelectorParsingStatus.Error; } } else { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttSelNoBar", mToken); }; return nsSelectorParsingStatus.Error; } } else if (mToken.IsSymbol('|')) { // NO namespace if (! GetToken(false)) { // premature EOF { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttributeNameEOF"); }; return nsSelectorParsingStatus.Error; } if (nsCSSTokenType.Ident == mToken.mType) { // attr name attr = mToken.mIdentStr; } else { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttributeNameExpected", mToken); }; UngetToken(); return nsSelectorParsingStatus.Error; } } else if (nsCSSTokenType.Ident == mToken.mType) { // attr name or namespace attr = mToken.mIdentStr; // hang on to it if (ExpectSymbol('|', false)) { // was a namespace nameSpaceID = GetNamespaceIdForPrefix(attr); if (nameSpaceID == nsNameSpace.Unknown) { return nsSelectorParsingStatus.Error; } if (! GetToken(false)) { // premature EOF { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttributeNameEOF"); }; return nsSelectorParsingStatus.Error; } if (nsCSSTokenType.Ident == mToken.mType) { // attr name attr = mToken.mIdentStr; } else { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttributeNameExpected", mToken); }; UngetToken(); return nsSelectorParsingStatus.Error; } } } else { // malformed { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttributeNameOrNamespaceExpected", mToken); }; UngetToken(); return nsSelectorParsingStatus.Error; } if (! GetToken(true)) { // premature EOF { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttSelInnerEOF"); }; return nsSelectorParsingStatus.Error; } if ((nsCSSTokenType.Symbol == mToken.mType) || (nsCSSTokenType.Includes == mToken.mType) || (nsCSSTokenType.Dashmatch == mToken.mType) || (nsCSSTokenType.Beginsmatch == mToken.mType) || (nsCSSTokenType.Endsmatch == mToken.mType) || (nsCSSTokenType.Containsmatch == mToken.mType)) { nsAttrFunc func; if (nsCSSTokenType.Includes == mToken.mType) { func = nsAttrFunc.Includes; } else if (nsCSSTokenType.Dashmatch == mToken.mType) { func = nsAttrFunc.DashMatch; } else if (nsCSSTokenType.Beginsmatch == mToken.mType) { func = nsAttrFunc.BeginsMatch; } else if (nsCSSTokenType.Endsmatch == mToken.mType) { func = nsAttrFunc.EndsMatch; } else if (nsCSSTokenType.Containsmatch == mToken.mType) { func = nsAttrFunc.ContainsMatch; } else if (']' == mToken.mSymbol) { aDataMask |= SEL_MASK_ATTRIB; aSelector.AddAttribute(nameSpaceID, attr); func = nsAttrFunc.Set; } else if ('=' == mToken.mSymbol) { func = nsAttrFunc.Equals; } else { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttSelUnexpected", mToken); }; UngetToken(); // bad function return nsSelectorParsingStatus.Error; } if (nsAttrFunc.Set != func) { // get value if (! GetToken(true)) { // premature EOF { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttSelValueEOF"); }; return nsSelectorParsingStatus.Error; } if ((nsCSSTokenType.Ident == mToken.mType) || (nsCSSTokenType.String == mToken.mType)) { string value = mToken.mIdentStr; if (! GetToken(true)) { // premature EOF { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttSelCloseEOF"); }; return nsSelectorParsingStatus.Error; } if (mToken.IsSymbol(']')) { bool isCaseSensitive = 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 == nsNameSpace.None) { /*TODO: static*/ string[] 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", // marquee null }; short i = 0; string htmlAttr; while ((htmlAttr = caseInsensitiveHTMLAttribute[i++]) != null) { if (attr.LowerCaseEqualsASCII(htmlAttr)) { isCaseSensitive = false; break; } } } aDataMask |= SEL_MASK_ATTRIB; aSelector.AddAttribute(nameSpaceID, attr, func, value, isCaseSensitive); } else { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttSelNoClose", mToken); }; UngetToken(); return nsSelectorParsingStatus.Error; } } else { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttSelBadValue", mToken); }; UngetToken(); return nsSelectorParsingStatus.Error; } } } else { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttSelUnexpected", mToken); }; UngetToken(); // bad dog, no biscut! return nsSelectorParsingStatus.Error; } return nsSelectorParsingStatus.Continue; }
static bool IsUniversalSelector(nsCSSSelector aSelector) { return ((bool)((aSelector.mNameSpace == nsNameSpace.Unknown) && (aSelector.mLowercaseTag == null) && (aSelector.mIDList == null) && (aSelector.mClassList == null) && (aSelector.mAttrList == null) && (aSelector.mNegations == null) && (aSelector.mPseudoClassList == null))); }
internal void SetDefaultNamespaceOnSelector(nsCSSSelector aSelector) { if (mNameSpaceMap != null) { aSelector.SetNameSpace(mNameSpaceMap.FindNameSpaceID(null)); } else { aSelector.SetNameSpace(nsNameSpace.Unknown); // wildcard } }
// // Parse a type element selector or a universal selector // namespace|type or namespace|* or *|* or * // internal nsSelectorParsingStatus ParseTypeOrUniversalSelector(ref int32_t aDataMask, nsCSSSelector aSelector, bool aIsNegated) { string buffer; if (mToken.IsSymbol('*')) { // universal element selector, or universal namespace if (ExpectSymbol('|', false)) { // was namespace aDataMask |= SEL_MASK_NSPACE; aSelector.SetNameSpace(nsNameSpace.Unknown); // namespace wildcard if (! GetToken(false)) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PETypeSelEOF"); }; return nsSelectorParsingStatus.Error; } if (nsCSSTokenType.Ident == mToken.mType) { // element name aDataMask |= SEL_MASK_ELEM; aSelector.SetTag(mToken.mIdentStr); } else if (mToken.IsSymbol('*')) { // universal selector aDataMask |= SEL_MASK_ELEM; // don't set tag } else { { if (!mSuppressErrors) mReporter.ReportUnexpected("PETypeSelNotType", mToken); }; UngetToken(); return nsSelectorParsingStatus.Error; } } else { // was universal element selector SetDefaultNamespaceOnSelector(aSelector); aDataMask |= SEL_MASK_ELEM; // don't set any tag in the selector } if (! GetToken(false)) { // premature eof is ok (here!) return nsSelectorParsingStatus.Done; } } else if (nsCSSTokenType.Ident == mToken.mType) { // element name or namespace name buffer = mToken.mIdentStr; // hang on to ident if (ExpectSymbol('|', false)) { // was namespace aDataMask |= SEL_MASK_NSPACE; int32_t nameSpaceID = GetNamespaceIdForPrefix(buffer); if (nameSpaceID == nsNameSpace.Unknown) { return nsSelectorParsingStatus.Error; } aSelector.SetNameSpace(nameSpaceID); if (! GetToken(false)) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PETypeSelEOF"); }; return nsSelectorParsingStatus.Error; } if (nsCSSTokenType.Ident == mToken.mType) { // element name aDataMask |= SEL_MASK_ELEM; aSelector.SetTag(mToken.mIdentStr); } else if (mToken.IsSymbol('*')) { // universal selector aDataMask |= SEL_MASK_ELEM; // don't set tag } else { { if (!mSuppressErrors) mReporter.ReportUnexpected("PETypeSelNotType", mToken); }; UngetToken(); return nsSelectorParsingStatus.Error; } } else { // was element name SetDefaultNamespaceOnSelector(aSelector); aSelector.SetTag(buffer); aDataMask |= SEL_MASK_ELEM; } if (! GetToken(false)) { // premature eof is ok (here!) return nsSelectorParsingStatus.Done; } } else if (mToken.IsSymbol('|')) { // No namespace aDataMask |= SEL_MASK_NSPACE; aSelector.SetNameSpace(nsNameSpace.None); // explicit NO namespace // get mandatory tag if (! GetToken(false)) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PETypeSelEOF"); }; return nsSelectorParsingStatus.Error; } if (nsCSSTokenType.Ident == mToken.mType) { // element name aDataMask |= SEL_MASK_ELEM; aSelector.SetTag(mToken.mIdentStr); } else if (mToken.IsSymbol('*')) { // universal selector aDataMask |= SEL_MASK_ELEM; // don't set tag } else { { if (!mSuppressErrors) mReporter.ReportUnexpected("PETypeSelNotType", mToken); }; UngetToken(); return nsSelectorParsingStatus.Error; } if (! GetToken(false)) { // premature eof is ok (here!) return nsSelectorParsingStatus.Done; } } else { SetDefaultNamespaceOnSelector(aSelector); } if (aIsNegated) { // restore last token read in case of a negated type selector UngetToken(); } return nsSelectorParsingStatus.Continue; }
// // 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; }
// // 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. // internal nsSelectorParsingStatus ParsePseudoClassWithSelectorListArg(nsCSSSelector aSelector, nsCSSPseudoClass aType) { var slist = new nsCSSSelectorList(); if (! ParseSelectorList(ref slist, ')')) { return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')') } // Check that none of the selectors in the list have combinators or // pseudo-elements. for (nsCSSSelectorList l = slist; l != null; l = l.mNext) { nsCSSSelector s = l.mSelectors; if (s.mNext != null || s.IsPseudoElement()) { return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')') } } // Add the pseudo with the selector list parameter aSelector.AddPseudoClass(aType, slist); // close the parenthesis if (!ExpectSymbol(')', true)) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassNoClose", mToken); }; return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')') } return nsSelectorParsingStatus.Continue; }
internal nsSelectorParsingStatus ParsePseudoClassWithNthPairArg(nsCSSSelector aSelector, nsCSSPseudoClass aType) { int32_t[] numbers = { 0, 0 }; bool lookForB = true; // Follow the whitespace rules as proposed in // http://lists.w3.org/Archives/Public/www-style/2008Mar/0121.html if (! GetToken(true)) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgEOF"); }; return nsSelectorParsingStatus.Error; } if (nsCSSTokenType.Ident == mToken.mType || nsCSSTokenType.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_t truncAt = 0; if (StringBeginsWith(mToken.mIdentStr, "n-")) { truncAt = 1; } else if (StringBeginsWith(mToken.mIdentStr, "-n-")) { truncAt = 2; } if (truncAt != 0) { mScanner.Backup(mToken.mIdentStr.Length() - truncAt); mToken.mIdentStr = mToken.mIdentStr.Substring(0, truncAt); } } if (nsCSSTokenType.Ident == mToken.mType) { if (mToken.mIdentStr.LowerCaseEqualsLiteral("odd")) { numbers[0] = 2; numbers[1] = 1; lookForB = false; } else if (mToken.mIdentStr.LowerCaseEqualsLiteral("even")) { numbers[0] = 2; numbers[1] = 0; lookForB = false; } else if (mToken.mIdentStr.LowerCaseEqualsLiteral("n")) { numbers[0] = 1; } else if (mToken.mIdentStr.LowerCaseEqualsLiteral("-n")) { numbers[0] = -1; } else { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgNotNth", mToken); }; return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')') } } else if (nsCSSTokenType.Number == mToken.mType) { if (!mToken.mIntegerValid) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgNotNth", mToken); }; return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')') } numbers[1] = mToken.mInteger; lookForB = false; } else if (nsCSSTokenType.Dimension == mToken.mType) { if (!mToken.mIntegerValid || !mToken.mIdentStr.LowerCaseEqualsLiteral("n")) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgNotNth", mToken); }; return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')') } numbers[0] = mToken.mInteger; } // XXX If it's a ')', is that valid? (as 0n+0) else { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgNotNth", mToken); }; UngetToken(); return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')') } if (! GetToken(true)) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgEOF"); }; return nsSelectorParsingStatus.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. bool haveSign = false; int32_t sign = 1; if (mToken.IsSymbol('+') || mToken.IsSymbol('-')) { haveSign = true; if (mToken.IsSymbol('-')) { sign = -1; } if (! GetToken(true)) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgEOF"); }; return nsSelectorParsingStatus.Error; } } if (nsCSSTokenType.Number != mToken.mType || !mToken.mIntegerValid || mToken.mHasSign == haveSign) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgNotNth", mToken); }; return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')') } numbers[1] = mToken.mInteger * sign; if (! GetToken(true)) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgEOF"); }; return nsSelectorParsingStatus.Error; } } if (!mToken.IsSymbol(')')) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassNoClose", mToken); }; return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')') } aSelector.AddPseudoClass(aType, numbers); return nsSelectorParsingStatus.Continue; }
// // Parse the argument of a pseudo-class that has an ident arg // internal nsSelectorParsingStatus ParsePseudoClassWithIdentArg(nsCSSSelector aSelector, nsCSSPseudoClass aType) { if (! GetToken(true)) { // premature eof { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgEOF"); }; return nsSelectorParsingStatus.Error; } // We expect an identifier with a language abbreviation if (nsCSSTokenType.Ident != mToken.mType) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgNotIdent", mToken); }; UngetToken(); return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')') } // -moz-locale-dir and -moz-dir can only have values of 'ltr' or 'rtl'. if (aType == nsCSSPseudoClass.MozLocaleDir || aType == nsCSSPseudoClass.Dir) { mToken.mIdentStr = mToken.mIdentStr.ToLower(); // case insensitive if (!mToken.mIdentStr.EqualsLiteral("ltr") && !mToken.mIdentStr.EqualsLiteral("rtl")) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEBadDirValue", mToken); }; return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')') } } // Add the pseudo with the language parameter aSelector.AddPseudoClass(aType, mToken.mIdentStr); // close the parenthesis if (!ExpectSymbol(')', true)) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassNoClose", mToken); }; return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')') } return nsSelectorParsingStatus.Continue; }
// // Parse the argument of a negation pseudo-class :not() // internal nsSelectorParsingStatus ParseNegatedSimpleSelector(ref int32_t aDataMask, nsCSSSelector aSelector) { if (! GetToken(true)) { // premature eof { if (!mSuppressErrors) mReporter.ReportUnexpected("PENegationEOF"); }; return nsSelectorParsingStatus.Error; } if (mToken.IsSymbol(')')) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PENegationBadArg", mToken); }; return nsSelectorParsingStatus.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 = new nsCSSSelector(); nsCSSSelector negations = aSelector; while (negations.mNegations != null) { negations = negations.mNegations; } negations.mNegations = newSel; nsSelectorParsingStatus parsingStatus; if (nsCSSTokenType.ID == mToken.mType) { // #id parsingStatus = ParseIDSelector(ref aDataMask, newSel); } else if (mToken.IsSymbol('.')) { // .class parsingStatus = ParseClassSelector(ref aDataMask, newSel); } else if (mToken.IsSymbol(':')) { // :pseudo { string _1 = null; nsCSSPseudoElement _2 = 0; parsingStatus = ParsePseudoSelector(ref aDataMask, newSel, true, ref _1, null, ref _2); } } else if (mToken.IsSymbol('[')) { // [attribute parsingStatus = ParseAttributeSelector(ref aDataMask, newSel); if (nsSelectorParsingStatus.Error == parsingStatus) { // Skip forward to the matching ']' SkipUntil(']'); } } else { // then it should be a type element or universal selector parsingStatus = ParseTypeOrUniversalSelector(ref aDataMask, newSel, true); } if (nsSelectorParsingStatus.Error == parsingStatus) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PENegationBadInner", mToken); }; SkipUntil(')'); return parsingStatus; } // close the parenthesis if (!ExpectSymbol(')', true)) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PENegationNoClose", mToken); }; SkipUntil(')'); return nsSelectorParsingStatus.Error; } Debug.Assert(newSel.mNameSpace == nsNameSpace.Unknown || (newSel.mIDList == null && newSel.mClassList == null && newSel.mPseudoClassList == null && newSel.mAttrList == null), "Need to fix the serialization code to deal with this"); return nsSelectorParsingStatus.Continue; }
// // Parses an ID selector #name // internal nsSelectorParsingStatus ParseIDSelector(ref int32_t aDataMask, nsCSSSelector aSelector) { Debug.Assert(!mToken.mIdentStr.IsEmpty(), "Empty mIdent in nsCSSTokenType.ID token?"); aDataMask |= SEL_MASK_ID; aSelector.AddID(mToken.mIdentStr); return nsSelectorParsingStatus.Continue; }
// // Parses a class selector .name // internal nsSelectorParsingStatus ParseClassSelector(ref int32_t aDataMask, nsCSSSelector aSelector) { if (! GetToken(false)) { // get ident { if (!mSuppressErrors) mReporter.ReportUnexpected("PEClassSelEOF"); }; return nsSelectorParsingStatus.Error; } if (nsCSSTokenType.Ident != mToken.mType) { // malformed selector { if (!mSuppressErrors) mReporter.ReportUnexpected("PEClassSelNotIdent", mToken); }; UngetToken(); return nsSelectorParsingStatus.Error; } aDataMask |= SEL_MASK_CLASS; aSelector.AddClass(mToken.mIdentStr); return nsSelectorParsingStatus.Continue; }
internal static IEnumerable <CssSelector> TraverseList(CssSelector @this) { return(@this.TraverseList(i => i.mNext)); }