protected virtual void ParseName(ItemFactory itemFactory, ITextProvider text, TokenStream tokens) { if (tokens.CurrentToken.TokenType == CssTokenType.Function && tokens.CurrentToken.Start == Colon.AfterEnd) { if (TextRange.CompareDecoded(tokens.CurrentToken.Start, tokens.CurrentToken.Length, text, "not(", ignoreCase: true)) { Function = itemFactory.CreateSpecific <PseudoFunctionNot>(this); } else if (TextRange.CompareDecoded(tokens.CurrentToken.Start, tokens.CurrentToken.Length, text, "matches(", ignoreCase: true)) { Function = itemFactory.CreateSpecific <PseudoFunctionMatches>(this); } else { Function = itemFactory.CreateSpecific <Function>(this); } Function.Parse(itemFactory, text, tokens); // Function name should be colorizer as pseudo-class Function.Context = CssClassifierContextCache.FromTypeEnum(CssClassifierContextType.PseudoClass); Function.FunctionName.Context = Function.Context; Children.Add(Function); } else { Children.AddParseError(ParseErrorType.PseudoClassNameMissing); } }
public void CssTextRange_CompareDecoded() { for (int i = 0; i < 2; i++) { #if !SUPPORT_ENCODED_CSS if (i == 0) { continue; } #endif // Try the same string with and without encoded/escaped chars string text = (i == 0) ? @"@na\mes\70 ace \66 \o\o 'www.\'f\6F \o\'.com';" : @"@namespace foo 'www.\'foo\'.com'"; ITextProvider tp = new StringTextProvider(text); TokenList tokens = Helpers.MakeTokens(tp); Assert.AreEqual("@", TextRange.GetDecodedText(tokens[0].Start, tokens[0].Length, tp, forStringToken: false)); Assert.AreEqual("namespace", TextRange.GetDecodedText(tokens[1].Start, tokens[1].Length, tp, forStringToken: false)); Assert.AreEqual("foo", TextRange.GetDecodedText(tokens[2].Start, tokens[2].Length, tp, forStringToken: false)); Assert.AreEqual(@"'www.'foo'.com'", TextRange.GetDecodedText(tokens[3].Start, tokens[3].Length, tp, forStringToken: false)); Assert.IsTrue(TextRange.CompareDecoded(tokens[1].Start, tokens[1].Length, tp, "namespace", ignoreCase: false)); Assert.IsFalse(TextRange.CompareDecoded(tokens[1].Start, tokens[1].Length, tp, "NAMEspace", ignoreCase: false)); Assert.IsTrue(TextRange.CompareDecoded(tokens[1].Start, tokens[1].Length, tp, "NAMEspace", ignoreCase: true)); Assert.IsFalse(TextRange.CompareDecoded(tokens[1].Start, tokens[1].Length, tp, "namespace-foobar", ignoreCase: true)); Assert.IsFalse(TextRange.CompareDecoded(tokens[1].Start, tokens[1].Length, tp, "@namespace", ignoreCase: true)); Assert.IsTrue(TextRange.CompareDecoded(tokens[2].Start, tokens[2].Length, tp, "foo", ignoreCase: false)); #if SUPPORT_ENCODED_CSS Assert.IsTrue(TextRange.CompareDecoded(tokens[3].Start, tokens[3].Length, tp, "'www.'FOO'.com'", ignoreCase: true)); #endif } }
public override bool Parse(ItemFactory itemFactory, ITextProvider text, TokenStream tokens) { if (tokens.CurrentToken.TokenType == CssTokenType.Identifier && TextRange.CompareDecoded(tokens.CurrentToken.Start, tokens.CurrentToken.Length, text, "and", true)) { MediaCombineOperator = Children.AddCurrentAndAdvance(tokens, CssClassifierContextType.MediaCombineOperator); } if (tokens.CurrentToken.TokenType == CssTokenType.OpenFunctionBrace) { OpenFunctionBrace = Children.AddCurrentAndAdvance(tokens, CssClassifierContextType.FunctionBrace); ParseFeatureName(itemFactory, text, tokens); if (tokens.CurrentToken.TokenType == CssTokenType.Colon) { Colon = Children.AddCurrentAndAdvance(tokens, CssClassifierContextType.Punctuation); } while (tokens.CurrentToken.TokenType != CssTokenType.CloseFunctionBrace && tokens.CurrentToken.TokenType != CssTokenType.OpenCurlyBrace && !tokens.CurrentToken.IsScopeBlocker()) { ParseNextValue(itemFactory, text, tokens); } if (tokens.CurrentToken.TokenType == CssTokenType.CloseFunctionBrace) { CloseFunctionBrace = Children.AddCurrentAndAdvance(tokens, CssClassifierContextType.FunctionBrace); } else { OpenFunctionBrace.AddParseError(ParseErrorType.CloseFunctionBraceMissing, ParseErrorLocation.AfterItem); } if ((Colon != null && Children[Children.Count - 1] == Colon) || (Colon != null && CloseFunctionBrace != null && Children.IndexOf(Colon) + 1 == Children.IndexOf(CloseFunctionBrace))) { // There was nothing between the colon and close brace Colon.AddParseError(ParseErrorType.PropertyValueMissing, ParseErrorLocation.AfterItem); } } if (MediaCombineOperator != null && OpenFunctionBrace == null) { MediaCombineOperator.AddParseError(ParseErrorType.MediaExpressionExpected, ParseErrorLocation.AfterItem); } return(Children.Count > 0); }
public override bool Parse(ItemFactory itemFactory, ITextProvider text, TokenStream tokens) { if (tokens.CurrentToken.TokenType == CssTokenType.Comma) { Comma = Children.AddCurrentAndAdvance(tokens, CssClassifierContextType.Default); } if (tokens.CurrentToken.TokenType == CssTokenType.Identifier) { if (TextRange.CompareDecoded(tokens.CurrentToken.Start, tokens.CurrentToken.Length, text, "only", ignoreCase: true) || TextRange.CompareDecoded(tokens.CurrentToken.Start, tokens.CurrentToken.Length, text, "not", ignoreCase: true)) { Operation = Children.AddCurrentAndAdvance(tokens, CssClassifierContextType.MediaQueryOperation); } } if (tokens.CurrentToken.TokenType == CssTokenType.Identifier && !IsMediaExpressionStart(text, tokens.CurrentToken)) { MediaType = Children.AddCurrentAndAdvance(tokens, CssClassifierContextType.MediaType); } else if (tokens.CurrentToken.TokenType != CssTokenType.OpenFunctionBrace) { Children.AddParseError(ParseErrorType.MediaTypeMissing); } while (!tokens.CurrentToken.IsDirectiveTerminator() && tokens.CurrentToken.TokenType != CssTokenType.Comma) { if (IsMediaExpressionStart(text, tokens.CurrentToken)) { MediaExpression mx = itemFactory.CreateSpecific <MediaExpression>(this); if (mx.Parse(itemFactory, text, tokens)) { Expressions.Add(mx); Children.Add(mx); } else { Children.AddUnknownAndAdvance(itemFactory, text, tokens, ParseErrorType.MediaExpressionExpected); } } else { Children.AddUnknownAndAdvance(itemFactory, text, tokens, ParseErrorType.UnexpectedMediaQueryToken); } } return(Children.Count > 0); }
internal static bool IsMediaExpressionStart(ITextProvider text, CssToken token) { switch (token.TokenType) { case CssTokenType.OpenFunctionBrace: return(true); case CssTokenType.Identifier: if (TextRange.CompareDecoded(token.Start, token.Length, text, "and", true)) { return(true); } break; } return(false); }
protected virtual void ParseBang(ItemFactory itemFactory, ITextProvider text, TokenStream tokens) { if (Bang == null) { Bang = Children.AddCurrentAndAdvance(tokens, CssClassifierContextType.Important); if (TextRange.CompareDecoded(tokens.CurrentToken.Start, tokens.CurrentToken.Length, text, "important", ignoreCase: true)) { Important = Children.AddCurrentAndAdvance(tokens, CssClassifierContextType.Important); } else { Children.AddParseError(ParseErrorType.ImportantMissing); } } else { Children.AddUnknownAndAdvance(itemFactory, text, tokens, ParseErrorType.UnexpectedBangInProperty); } }
public override bool Parse(ItemFactory itemFactory, ITextProvider text, TokenStream tokens) { switch (tokens.CurrentToken.TokenType) { case CssTokenType.Identifier: if (TextRange.CompareDecoded(tokens.CurrentToken.Start, tokens.CurrentToken.Length, text, "from", true)) { SelectorType = KeyFrameSelectorType.From; Name = Children.AddCurrentAndAdvance(tokens, null); } else if (TextRange.CompareDecoded(tokens.CurrentToken.Start, tokens.CurrentToken.Length, text, "to", true)) { SelectorType = KeyFrameSelectorType.To; Name = Children.AddCurrentAndAdvance(tokens, null); } break; case CssTokenType.Number: // Must be a percentage: if (tokens.Peek(1).TokenType == CssTokenType.Units && TextRange.Compare(tokens.Peek(1).Start, tokens.Peek(1).Length, text, "%", ignoreCase: false)) { UnitValue uv = new UnitValue(); if (uv.Parse(itemFactory, text, tokens)) { SelectorType = KeyFrameSelectorType.Percentage; Children.Add(uv); } } break; } if (tokens.CurrentToken.TokenType == CssTokenType.Comma && Children.Count > 0) { Comma = Children.AddCurrentAndAdvance(tokens, CssClassifierContextType.Punctuation); } return(Children.Count > 0); }
internal static Function ParseFunction(ComplexItem parent, ItemFactory itemFactory, ITextProvider text, TokenStream tokens) { Function fn; if (TextRange.CompareDecoded(tokens.CurrentToken.Start, tokens.CurrentToken.Length, text, "rgb(", ignoreCase: true)) { fn = itemFactory.CreateSpecific <FunctionColor>(parent); ((FunctionColor)fn).ColorFunction = ColorFunctionType.Rgb; } else if (TextRange.CompareDecoded(tokens.CurrentToken.Start, tokens.CurrentToken.Length, text, "rgba(", ignoreCase: true)) { fn = itemFactory.CreateSpecific <FunctionColor>(parent); ((FunctionColor)fn).ColorFunction = ColorFunctionType.Rgba; } else if (TextRange.CompareDecoded(tokens.CurrentToken.Start, tokens.CurrentToken.Length, text, "hsl(", ignoreCase: true)) { fn = itemFactory.CreateSpecific <FunctionColor>(parent); ((FunctionColor)fn).ColorFunction = ColorFunctionType.Hsl; } else if (TextRange.CompareDecoded(tokens.CurrentToken.Start, tokens.CurrentToken.Length, text, "hsla(", ignoreCase: true)) { fn = itemFactory.CreateSpecific <FunctionColor>(parent); ((FunctionColor)fn).ColorFunction = ColorFunctionType.Hsla; } else if (TextRange.CompareDecoded(tokens.CurrentToken.Start, tokens.CurrentToken.Length, text, "attr(", ignoreCase: true)) { fn = itemFactory.CreateSpecific <FunctionAttr>(parent); } else if (TextRange.CompareDecoded(tokens.CurrentToken.Start, tokens.CurrentToken.Length, text, "calc(", ignoreCase: true)) { fn = itemFactory.CreateSpecific <FunctionCalc>(parent); } else if (TextRange.CompareDecoded(tokens.CurrentToken.Start, tokens.CurrentToken.Length, text, "counter(", ignoreCase: true)) { fn = itemFactory.CreateSpecific <FunctionCounter>(parent); } else if (TextRange.CompareDecoded(tokens.CurrentToken.Start, tokens.CurrentToken.Length, text, "expression(", ignoreCase: true)) { fn = itemFactory.CreateSpecific <FunctionExpression>(parent); } else if (TextRange.CompareDecoded(tokens.CurrentToken.Start, tokens.CurrentToken.Length, text, "format(", ignoreCase: true)) { fn = itemFactory.CreateSpecific <FunctionFormat>(parent); } else if (TextRange.CompareDecoded(tokens.CurrentToken.Start, tokens.CurrentToken.Length, text, "local(", ignoreCase: true)) { fn = itemFactory.CreateSpecific <FunctionLocal>(parent); } else if (TextRange.CompareDecoded(tokens.CurrentToken.Start, tokens.CurrentToken.Length, text, "var(", ignoreCase: true)) { fn = itemFactory.CreateSpecific <FunctionVar>(parent); } else { fn = itemFactory.CreateSpecific <Function>(parent); } if (fn != null && !fn.Parse(itemFactory, text, tokens)) { fn = null; } return(fn); }
internal static ParseItem ParseDirective(ComplexItem parent, ItemFactory itemFactory, ITextProvider text, TokenStream tokens) { Debug.Assert(tokens.CurrentToken.TokenType == CssTokenType.At); CssToken atToken = tokens.CurrentToken; CssToken nameToken = tokens.Peek(1); ParseItem pi = null; if (nameToken.TokenType == CssTokenType.At && AllowDoubleAt(text)) { // Ignore the first @ in @@directive atToken = nameToken; nameToken = tokens.Peek(2); } if (nameToken.TokenType == CssTokenType.Identifier && nameToken.Start == atToken.AfterEnd) { if ("charset".Length == nameToken.Length && text.CompareTo(nameToken.Start, "charset", ignoreCase: false)) { // must be lowercase, and not encoded pi = itemFactory.Create <CharsetDirective>(parent); } else if ("import".Length == nameToken.Length && text.CompareTo(nameToken.Start, "import", ignoreCase: true)) { pi = itemFactory.Create <ImportDirective>(parent); } else if ("page".Length == nameToken.Length && text.CompareTo(nameToken.Start, "page", ignoreCase: true)) { pi = itemFactory.Create <PageDirective>(parent); } else if ("media".Length == nameToken.Length && text.CompareTo(nameToken.Start, "media", ignoreCase: true)) { pi = itemFactory.Create <MediaDirective>(parent); } else if ("namespace".Length == nameToken.Length && text.CompareTo(nameToken.Start, "namespace", ignoreCase: true)) { // CSS3 Namespaces // http://www.w3.org/TR/css3-namespace/ pi = itemFactory.Create <NamespaceDirective>(parent); } else if (TextRange.CompareDecoded(nameToken.Start, nameToken.Length, text, "keyframes", ignoreCase: true) || TextRange.CompareDecoded(nameToken.Start, nameToken.Length, text, "-moz-keyframes", ignoreCase: true) || TextRange.CompareDecoded(nameToken.Start, nameToken.Length, text, "-ms-keyframes", ignoreCase: true) || TextRange.CompareDecoded(nameToken.Start, nameToken.Length, text, "-o-keyframes", ignoreCase: true) || TextRange.CompareDecoded(nameToken.Start, nameToken.Length, text, "-webkit-keyframes", ignoreCase: true)) { // CSS3 Animations // http://www.w3.org/TR/2009/WD-css3-animations-20090320/ pi = itemFactory.Create <KeyFramesDirective>(parent); } else if (TextRange.CompareDecoded(nameToken.Start, nameToken.Length, text, "font-face", ignoreCase: true)) { // CSS3 Webfonts // http://www.w3.org/TR/2002/WD-css3-webfonts-20020802/#font-descriptions pi = itemFactory.Create <FontFaceDirective>(parent); } else if (TextRange.CompareDecoded(nameToken.Start, nameToken.Length, text, "counter", ignoreCase: true)) { pi = itemFactory.Create <CounterDirective>(parent); } else if (TextRange.CompareDecoded(nameToken.Start, nameToken.Length, text, "viewport", ignoreCase: true)) { pi = itemFactory.Create <ViewportDirective>(parent); } } if (pi == null) { // some other stuff, like @top-center/left/top/middle... or @footnoote in CSS3 pi = itemFactory.Create <UnknownDirective>(parent); } pi.Parse(itemFactory, text, tokens); return(pi); }
public override bool Parse(ItemFactory itemFactory, ITextProvider text, TokenStream tokens) { if (tokens.CurrentToken.TokenType == CssTokenType.At) { ParseAtAndKeyword(itemFactory, text, tokens); // all lowercase per W3C BNF if (Keyword == null) { Children.AddParseError(ParseErrorType.AtDirectiveNameMissing); } else if (TextRange.CompareDecoded(Keyword.Start, Keyword.Length, text, "top-left-corner", ignoreCase: false)) { DirectiveType = MarginDirectiveType.TopLeftCorner; } else if (TextRange.CompareDecoded(Keyword.Start, Keyword.Length, text, "top-left", ignoreCase: false)) { DirectiveType = MarginDirectiveType.TopLeft; } else if (TextRange.CompareDecoded(Keyword.Start, Keyword.Length, text, "top-center", ignoreCase: false)) { DirectiveType = MarginDirectiveType.TopCenter; } else if (TextRange.CompareDecoded(Keyword.Start, Keyword.Length, text, "top-right", ignoreCase: false)) { DirectiveType = MarginDirectiveType.TopRight; } else if (TextRange.CompareDecoded(Keyword.Start, Keyword.Length, text, "top-right-corner", ignoreCase: false)) { DirectiveType = MarginDirectiveType.TopRightCorner; } else if (TextRange.CompareDecoded(Keyword.Start, Keyword.Length, text, "bottom-left-corner", ignoreCase: false)) { DirectiveType = MarginDirectiveType.BottomLeftCorner; } else if (TextRange.CompareDecoded(Keyword.Start, Keyword.Length, text, "bottom-left", ignoreCase: false)) { DirectiveType = MarginDirectiveType.BottomLeft; } else if (TextRange.CompareDecoded(Keyword.Start, Keyword.Length, text, "bottom-center", ignoreCase: false)) { DirectiveType = MarginDirectiveType.BottomCenter; } else if (TextRange.CompareDecoded(Keyword.Start, Keyword.Length, text, "bottom-right", ignoreCase: false)) { DirectiveType = MarginDirectiveType.BottomRight; } else if (TextRange.CompareDecoded(Keyword.Start, Keyword.Length, text, "bottom-right-corner", ignoreCase: false)) { DirectiveType = MarginDirectiveType.BottomRightCorner; } else if (TextRange.CompareDecoded(Keyword.Start, Keyword.Length, text, "left-top", ignoreCase: false)) { DirectiveType = MarginDirectiveType.LeftTop; } else if (TextRange.CompareDecoded(Keyword.Start, Keyword.Length, text, "left-middle", ignoreCase: false)) { DirectiveType = MarginDirectiveType.LeftMiddle; } else if (TextRange.CompareDecoded(Keyword.Start, Keyword.Length, text, "left-bottom", ignoreCase: false)) { DirectiveType = MarginDirectiveType.LeftBottom; } else if (TextRange.CompareDecoded(Keyword.Start, Keyword.Length, text, "right-top", ignoreCase: false)) { DirectiveType = MarginDirectiveType.RightTop; } else if (TextRange.CompareDecoded(Keyword.Start, Keyword.Length, text, "right-middle", ignoreCase: false)) { DirectiveType = MarginDirectiveType.RightMiddle; } else if (TextRange.CompareDecoded(Keyword.Start, Keyword.Length, text, "right-bottom", ignoreCase: false)) { DirectiveType = MarginDirectiveType.RightBottom; } else { DirectiveType = MarginDirectiveType.Unknown; } } RuleBlock = itemFactory.CreateSpecific <RuleBlock>(this); if (!ParseBlock(RuleBlock, itemFactory, text, tokens)) { RuleBlock = null; } return(Children.Count > 0); }