AngleSharp by AngleSharp

<PackageReference Include="AngleSharp" Version="0.9.9.1" />

 CssBuilder

sealed class CssBuilder
See http://dev.w3.org/csswg/css-syntax/#parsing for details.
using AngleSharp.Css; using AngleSharp.Css.Values; using AngleSharp.Dom; using AngleSharp.Dom.Collections; using AngleSharp.Dom.Css; using AngleSharp.Extensions; using AngleSharp.Services.Default; using System; using System.Collections.Generic; using System.Text; namespace AngleSharp.Parser.Css { internal sealed class CssBuilder { private readonly CssTokenizer _tokenizer; private readonly CssParser _parser; private readonly Stack<CssNode> _nodes; public CssBuilder(CssTokenizer tokenizer, CssParser parser) { _tokenizer = tokenizer; _parser = parser; _nodes = new Stack<CssNode>(); } public CssRule CreateAtRule(CssToken token) { if (token.Data.Is(RuleNames.Media)) return CreateMedia(token); if (token.Data.Is(RuleNames.FontFace)) return CreateFontFace(token); if (token.Data.Is(RuleNames.Keyframes)) return CreateKeyframes(token); if (token.Data.Is(RuleNames.Import)) return CreateImport(token); if (token.Data.Is(RuleNames.Charset)) return CreateCharset(token); if (token.Data.Is(RuleNames.Namespace)) return CreateNamespace(token); if (token.Data.Is(RuleNames.Page)) return CreatePage(token); if (token.Data.Is(RuleNames.Supports)) return CreateSupports(token); if (token.Data.Is(RuleNames.ViewPort)) return CreateViewport(token); if (token.Data.Is(RuleNames.Document)) return CreateDocument(token); return CreateUnknown(token); } public CssRule CreateRule(CssToken token) { switch (token.Type) { case CssTokenType.AtKeyword: return CreateAtRule(token); case CssTokenType.CurlyBracketOpen: RaiseErrorOccurred(CssParseError.InvalidBlockStart, token.Position); JumpToRuleEnd(ref token); return null; case CssTokenType.String: case CssTokenType.Url: case CssTokenType.RoundBracketClose: case CssTokenType.CurlyBracketClose: case CssTokenType.SquareBracketClose: RaiseErrorOccurred(CssParseError.InvalidToken, token.Position); JumpToRuleEnd(ref token); return null; default: return CreateStyle(token); } } public CssRule CreateCharset(CssToken current) { CssCharsetRule cssCharsetRule = new CssCharsetRule(_parser); TextPosition position = current.Position; CssToken token = NextToken(); _nodes.Push(cssCharsetRule); CollectTrivia(ref token); if (token.Type == CssTokenType.String) cssCharsetRule.CharacterSet = token.Data; JumpToEnd(ref token); cssCharsetRule.SourceCode = CreateView(position, token.Position); _nodes.Pop(); return cssCharsetRule; } public CssRule CreateDocument(CssToken current) { CssDocumentRule rule = new CssDocumentRule(_parser); TextPosition position = current.Position; CssToken token = NextToken(); _nodes.Push(rule); CollectTrivia(ref token); FillFunctions(delegate(DocumentFunction function) { rule.AppendChild(function); }, ref token); CollectTrivia(ref token); if (token.Type == CssTokenType.CurlyBracketOpen) { TextPosition end = FillRules(rule); rule.SourceCode = CreateView(position, end); _nodes.Pop(); return rule; } _nodes.Pop(); return SkipDeclarations(token); } public CssRule CreateViewport(CssToken current) { CssViewportRule cssViewportRule = new CssViewportRule(_parser); TextPosition position = current.Position; CssToken token = NextToken(); _nodes.Push(cssViewportRule); CollectTrivia(ref token); if (token.Type == CssTokenType.CurlyBracketOpen) { CssViewportRule rule = cssViewportRule; CssPropertyFactory properties = Factory.Properties; TextPosition end = FillDeclarations(rule, properties.CreateViewport); cssViewportRule.SourceCode = CreateView(position, end); _nodes.Pop(); return cssViewportRule; } _nodes.Pop(); return SkipDeclarations(token); } public CssRule CreateFontFace(CssToken current) { CssFontFaceRule cssFontFaceRule = new CssFontFaceRule(_parser); TextPosition position = current.Position; CssToken token = NextToken(); _nodes.Push(cssFontFaceRule); CollectTrivia(ref token); if (token.Type == CssTokenType.CurlyBracketOpen) { CssFontFaceRule rule = cssFontFaceRule; CssPropertyFactory properties = Factory.Properties; TextPosition end = FillDeclarations(rule, properties.CreateFont); cssFontFaceRule.SourceCode = CreateView(position, end); _nodes.Pop(); return cssFontFaceRule; } _nodes.Pop(); return SkipDeclarations(token); } public CssRule CreateImport(CssToken current) { CssImportRule cssImportRule = new CssImportRule(_parser); TextPosition position = current.Position; CssToken token = NextToken(); _nodes.Push(cssImportRule); CollectTrivia(ref token); if (token.Is(CssTokenType.String, CssTokenType.Url)) { cssImportRule.Href = token.Data; token = NextToken(); CollectTrivia(ref token); FillMediaList(cssImportRule.Media, CssTokenType.Semicolon, ref token); } CollectTrivia(ref token); JumpToEnd(ref token); cssImportRule.SourceCode = CreateView(position, token.Position); _nodes.Pop(); return cssImportRule; } public CssRule CreateKeyframes(CssToken current) { CssKeyframesRule cssKeyframesRule = new CssKeyframesRule(_parser); TextPosition position = current.Position; CssToken token = NextToken(); _nodes.Push(cssKeyframesRule); CollectTrivia(ref token); cssKeyframesRule.Name = GetRuleName(ref token); CollectTrivia(ref token); if (token.Type == CssTokenType.CurlyBracketOpen) { TextPosition end = FillKeyframeRules(cssKeyframesRule); cssKeyframesRule.SourceCode = CreateView(position, end); _nodes.Pop(); return cssKeyframesRule; } _nodes.Pop(); return SkipDeclarations(token); } public CssRule CreateMedia(CssToken current) { CssMediaRule cssMediaRule = new CssMediaRule(_parser); TextPosition position = current.Position; CssToken token = NextToken(); _nodes.Push(cssMediaRule); CollectTrivia(ref token); FillMediaList(cssMediaRule.Media, CssTokenType.CurlyBracketOpen, ref token); CollectTrivia(ref token); if (token.Type != CssTokenType.CurlyBracketOpen) { while (token.Type != CssTokenType.EndOfFile) { if (token.Type == CssTokenType.Semicolon) { _nodes.Pop(); return null; } if (token.Type == CssTokenType.CurlyBracketOpen) break; token = NextToken(); } } TextPosition end = FillRules(cssMediaRule); cssMediaRule.SourceCode = CreateView(position, end); _nodes.Pop(); return cssMediaRule; } public CssRule CreateNamespace(CssToken current) { CssNamespaceRule cssNamespaceRule = new CssNamespaceRule(_parser); TextPosition position = current.Position; CssToken token = NextToken(); _nodes.Push(cssNamespaceRule); CollectTrivia(ref token); cssNamespaceRule.Prefix = GetRuleName(ref token); CollectTrivia(ref token); if (token.Type == CssTokenType.Url) cssNamespaceRule.NamespaceUri = token.Data; JumpToEnd(ref token); cssNamespaceRule.SourceCode = CreateView(position, token.Position); _nodes.Pop(); return cssNamespaceRule; } public CssRule CreatePage(CssToken current) { CssPageRule cssPageRule = new CssPageRule(_parser); TextPosition position = current.Position; CssToken token = NextToken(); _nodes.Push(cssPageRule); CollectTrivia(ref token); cssPageRule.Selector = CreateSelector(ref token); CollectTrivia(ref token); if (token.Type == CssTokenType.CurlyBracketOpen) { TextPosition end = FillDeclarations(cssPageRule.Style); cssPageRule.SourceCode = CreateView(position, end); _nodes.Pop(); return cssPageRule; } _nodes.Pop(); return SkipDeclarations(token); } public CssRule CreateSupports(CssToken current) { CssSupportsRule cssSupportsRule = new CssSupportsRule(_parser); TextPosition position = current.Position; CssToken token = NextToken(); _nodes.Push(cssSupportsRule); CollectTrivia(ref token); cssSupportsRule.Condition = AggregateCondition(ref token); CollectTrivia(ref token); if (token.Type == CssTokenType.CurlyBracketOpen) { TextPosition end = FillRules(cssSupportsRule); cssSupportsRule.SourceCode = CreateView(position, end); _nodes.Pop(); return cssSupportsRule; } _nodes.Pop(); return SkipDeclarations(token); } public CssRule CreateStyle(CssToken current) { CssStyleRule cssStyleRule = new CssStyleRule(_parser); TextPosition position = current.Position; _nodes.Push(cssStyleRule); CollectTrivia(ref current); cssStyleRule.Selector = CreateSelector(ref current); TextPosition end = FillDeclarations(cssStyleRule.Style); cssStyleRule.SourceCode = CreateView(position, end); _nodes.Pop(); if (cssStyleRule.Selector == null) return null; return cssStyleRule; } public CssKeyframeRule CreateKeyframeRule(CssToken current) { CssKeyframeRule cssKeyframeRule = new CssKeyframeRule(_parser); TextPosition position = current.Position; _nodes.Push(cssKeyframeRule); CollectTrivia(ref current); cssKeyframeRule.Key = CreateKeyframeSelector(ref current); TextPosition end = FillDeclarations(cssKeyframeRule.Style); cssKeyframeRule.SourceCode = CreateView(position, end); _nodes.Pop(); if (cssKeyframeRule.Key == null) return null; return cssKeyframeRule; } public CssRule CreateUnknown(CssToken current) { TextPosition position = current.Position; if (_parser.Options.IsIncludingUnknownRules) { CssToken cssToken = NextToken(); CssUnknownRule cssUnknownRule = new CssUnknownRule(current.Data, _parser); _nodes.Push(cssUnknownRule); while (cssToken.IsNot(CssTokenType.CurlyBracketOpen, CssTokenType.Semicolon, CssTokenType.EndOfFile)) { cssToken = NextToken(); } if (cssToken.Type == CssTokenType.CurlyBracketOpen) { int num = 1; do { cssToken = NextToken(); switch (cssToken.Type) { case CssTokenType.CurlyBracketOpen: num++; break; case CssTokenType.CurlyBracketClose: num--; break; case CssTokenType.EndOfFile: num = 0; break; } } while (num != 0); } cssUnknownRule.SourceCode = CreateView(position, cssToken.Position); _nodes.Pop(); return cssUnknownRule; } RaiseErrorOccurred(CssParseError.UnknownAtRule, position); JumpToRuleEnd(ref current); return null; } public CssValue CreateValue(ref CssToken token) { bool important = false; return CreateValue(CssTokenType.CurlyBracketClose, ref token, out important); } public List<CssMedium> CreateMedia(ref CssToken token) { List<CssMedium> list = new List<CssMedium>(); CollectTrivia(ref token); while (token.Type != CssTokenType.EndOfFile) { CssMedium cssMedium = CreateMedium(ref token); if (cssMedium == null || token.IsNot(CssTokenType.Comma, CssTokenType.EndOfFile)) throw new DomException(DomError.Syntax); token = NextToken(); CollectTrivia(ref token); list.Add(cssMedium); } return list; } public TextPosition CreateRules(CssStyleSheet sheet) { CssToken token = NextToken(); _nodes.Push(sheet); CollectTrivia(ref token); while (token.Type != CssTokenType.EndOfFile) { CssRule rule = CreateRule(token); token = NextToken(); CollectTrivia(ref token); sheet.Rules.Add(rule); } _nodes.Pop(); return token.Position; } public IConditionFunction CreateCondition(ref CssToken token) { CollectTrivia(ref token); return AggregateCondition(ref token); } public KeyframeSelector CreateKeyframeSelector(ref CssToken token) { List<Percent> list = new List<Percent>(); bool flag = true; TextPosition position = token.Position; CollectTrivia(ref token); while (token.Type != CssTokenType.EndOfFile) { if (list.Count > 0) { if (token.Type == CssTokenType.CurlyBracketOpen) break; if (token.Type != CssTokenType.Comma) flag = false; else token = NextToken(); CollectTrivia(ref token); } if (token.Type == CssTokenType.Percentage) list.Add(new Percent(((CssUnitToken)token).Value)); else if (token.Type == CssTokenType.Ident && token.Data.Is(Keywords.From)) { list.Add(Percent.Zero); } else if (token.Type == CssTokenType.Ident && token.Data.Is(Keywords.To)) { list.Add(Percent.Hundred); } else { flag = false; } token = NextToken(); CollectTrivia(ref token); } if (!flag) RaiseErrorOccurred(CssParseError.InvalidSelector, position); return new KeyframeSelector(list); } public List<DocumentFunction> CreateFunctions(ref CssToken token) { List<DocumentFunction> functions = new List<DocumentFunction>(); CollectTrivia(ref token); FillFunctions(delegate(DocumentFunction function) { functions.Add(function); }, ref token); return functions; } public TextPosition FillDeclarations(CssStyleDeclaration style) { CssToken token = NextToken(); _nodes.Push(style); CollectTrivia(ref token); while (token.IsNot(CssTokenType.EndOfFile, CssTokenType.CurlyBracketClose)) { CssPropertyFactory properties = Factory.Properties; CssProperty cssProperty = CreateDeclarationWith(properties.Create, ref token); if (cssProperty != null && cssProperty.HasValue) style.SetProperty(cssProperty); CollectTrivia(ref token); } _nodes.Pop(); return token.Position; } public CssProperty CreateDeclarationWith(Func<string, CssProperty> createProperty, ref CssToken token) { CssProperty cssProperty = null; StringBuilder stringBuilder = Pool.NewStringBuilder(); TextPosition position = token.Position; while (token.IsDeclarationName()) { stringBuilder.Append(token.ToValue()); token = NextToken(); } string text = stringBuilder.ToPool(); object obj; if (text.Length > 0) { CssParserOptions options = _parser.Options; if (!options.IsIncludingUnknownDeclarations) { options = _parser.Options; if (!options.IsToleratingInvalidValues) { obj = createProperty(text); goto IL_007f; } } obj = new CssUnknownProperty(text); goto IL_007f; } if (token.Type != CssTokenType.EndOfFile) { RaiseErrorOccurred(CssParseError.IdentExpected, position); JumpToDeclEnd(ref token); } goto IL_0131; IL_007f: cssProperty = (CssProperty)obj; if (cssProperty == null) RaiseErrorOccurred(CssParseError.UnknownDeclarationName, position); else _nodes.Push(cssProperty); CollectTrivia(ref token); if (token.Type == CssTokenType.Colon) { bool important = false; CssValue cssValue = CreateValue(CssTokenType.CurlyBracketClose, ref token, out important); if (cssValue == null) RaiseErrorOccurred(CssParseError.ValueMissing, token.Position); else if (cssProperty != null && cssProperty.TrySetValue(cssValue)) { cssProperty.IsImportant = important; } CollectTrivia(ref token); } else RaiseErrorOccurred(CssParseError.ColonMissing, token.Position); JumpToDeclEnd(ref token); if (cssProperty != null) _nodes.Pop(); goto IL_0131; IL_0131: if (token.Type == CssTokenType.Semicolon) token = NextToken(); return cssProperty; } public CssProperty CreateDeclaration(ref CssToken token) { CollectTrivia(ref token); CssPropertyFactory properties = Factory.Properties; return CreateDeclarationWith(properties.Create, ref token); } public CssMedium CreateMedium(ref CssToken token) { CssMedium cssMedium = new CssMedium(); CollectTrivia(ref token); if (token.Type == CssTokenType.Ident) { string data = token.Data; if (data.Isi(Keywords.Not)) { cssMedium.IsInverse = true; token = NextToken(); CollectTrivia(ref token); } else if (data.Isi(Keywords.Only)) { cssMedium.IsExclusive = true; token = NextToken(); CollectTrivia(ref token); } } if (token.Type == CssTokenType.Ident) { cssMedium.Type = token.Data; token = NextToken(); CollectTrivia(ref token); if (token.Type != CssTokenType.Ident || !token.Data.Isi(Keywords.And)) return cssMedium; token = NextToken(); CollectTrivia(ref token); } do { if (token.Type != CssTokenType.RoundBracketOpen) return null; token = NextToken(); CollectTrivia(ref token); MediaFeature mediaFeature = CreateFeature(ref token); if (mediaFeature != null) cssMedium.AppendChild(mediaFeature); if (token.Type != CssTokenType.RoundBracketClose) return null; token = NextToken(); CollectTrivia(ref token); if (mediaFeature == null) return null; if (token.Type != CssTokenType.Ident || !token.Data.Isi(Keywords.And)) break; token = NextToken(); CollectTrivia(ref token); } while (token.Type != CssTokenType.EndOfFile); return cssMedium; } private void JumpToEnd(ref CssToken current) { while (current.IsNot(CssTokenType.EndOfFile, CssTokenType.Semicolon)) { current = NextToken(); } } private void JumpToRuleEnd(ref CssToken current) { int num = 0; while (current.Type != CssTokenType.EndOfFile) { if (current.Type == CssTokenType.CurlyBracketOpen) num++; else if (current.Type == CssTokenType.CurlyBracketClose) { num--; } if (num <= 0 && current.Is(CssTokenType.CurlyBracketClose, CssTokenType.Semicolon)) break; current = NextToken(); } } private void JumpToArgEnd(ref CssToken current) { int num = 0; while (current.Type != CssTokenType.EndOfFile) { if (current.Type == CssTokenType.RoundBracketOpen) num++; else { if (num <= 0 && current.Type == CssTokenType.RoundBracketClose) break; if (current.Type == CssTokenType.RoundBracketClose) num--; } current = NextToken(); } } private void JumpToDeclEnd(ref CssToken current) { int num = 0; while (current.Type != CssTokenType.EndOfFile) { if (current.Type == CssTokenType.CurlyBracketOpen) num++; else { if (num <= 0 && current.Is(CssTokenType.CurlyBracketClose, CssTokenType.Semicolon)) break; if (current.Type == CssTokenType.CurlyBracketClose) num--; } current = NextToken(); } } private CssToken NextToken() { return _tokenizer.Get(); } private TextView CreateView(TextPosition start, TextPosition end) { return new TextView(new TextRange(start, end), _tokenizer.Source); } private void CollectTrivia(ref CssToken token) { bool isStoringTrivia = _parser.Options.IsStoringTrivia; while (token.Type == CssTokenType.Whitespace || token.Type == CssTokenType.Comment || token.Type == CssTokenType.Cdc || token.Type == CssTokenType.Cdo) { if (isStoringTrivia && token.Type == CssTokenType.Comment) { CssNode cssNode = _nodes.Peek(); CssComment cssComment = new CssComment(token.Data); TextPosition position = token.Position; cssComment.SourceCode = CreateView(end: position.After(token.ToValue()), start: position); cssNode.AppendChild(cssComment); } token = _tokenizer.Get(); } } private CssRule SkipDeclarations(CssToken token) { RaiseErrorOccurred(CssParseError.InvalidToken, token.Position); JumpToRuleEnd(ref token); return null; } private void RaiseErrorOccurred(CssParseError code, TextPosition position) { _tokenizer.RaiseErrorOccurred(code, position); } private IConditionFunction AggregateCondition(ref CssToken token) { IConditionFunction conditionFunction = ExtractCondition(ref token); if (conditionFunction != null) { CollectTrivia(ref token); string data = token.Data; Func<IEnumerable<IConditionFunction>, IConditionFunction> creator = data.GetCreator(); if (creator != null) { token = NextToken(); CollectTrivia(ref token); List<IConditionFunction> arg = MultipleConditions(conditionFunction, data, ref token); conditionFunction = creator(arg); } } return conditionFunction; } private IConditionFunction ExtractCondition(ref CssToken token) { if (token.Type == CssTokenType.RoundBracketOpen) { token = NextToken(); CollectTrivia(ref token); IConditionFunction conditionFunction = AggregateCondition(ref token); if (conditionFunction != null) conditionFunction = new GroupCondition { Content = conditionFunction }; else if (token.Type == CssTokenType.Ident) { conditionFunction = DeclarationCondition(ref token); } if (token.Type == CssTokenType.RoundBracketClose) { token = NextToken(); CollectTrivia(ref token); } return conditionFunction; } if (token.Data.Isi(Keywords.Not)) { NotCondition notCondition = new NotCondition(); token = NextToken(); CollectTrivia(ref token); notCondition.Content = ExtractCondition(ref token); return notCondition; } return null; } private IConditionFunction DeclarationCondition(ref CssToken token) { CssProperty cssProperty = Factory.Properties.Create(token.Data) ?? new CssUnknownProperty(token.Data); DeclarationCondition result = null; token = NextToken(); CollectTrivia(ref token); if (token.Type == CssTokenType.Colon) { bool important = false; CssValue cssValue = CreateValue(CssTokenType.RoundBracketClose, ref token, out important); cssProperty.IsImportant = important; if (cssValue != null) result = new DeclarationCondition(cssProperty, cssValue); } return result; } private List<IConditionFunction> MultipleConditions(IConditionFunction condition, string connector, ref CssToken token) { List<IConditionFunction> list = new List<IConditionFunction>(); CollectTrivia(ref token); list.Add(condition); while (token.Type != CssTokenType.EndOfFile) { condition = ExtractCondition(ref token); if (condition == null) break; list.Add(condition); if (!token.Data.Isi(connector)) break; token = NextToken(); CollectTrivia(ref token); } return list; } private void FillFunctions(Action<DocumentFunction> add, ref CssToken token) { do { DocumentFunction documentFunction = token.ToDocumentFunction(); if (documentFunction == null) break; token = NextToken(); CollectTrivia(ref token); add(documentFunction); if (token.Type != CssTokenType.Comma) break; token = NextToken(); CollectTrivia(ref token); } while (token.Type != CssTokenType.EndOfFile); } private TextPosition FillKeyframeRules(CssKeyframesRule parentRule) { CssToken token = NextToken(); CollectTrivia(ref token); while (token.IsNot(CssTokenType.EndOfFile, CssTokenType.CurlyBracketClose)) { CssKeyframeRule rule = CreateKeyframeRule(token); token = NextToken(); CollectTrivia(ref token); parentRule.Rules.Add(rule); } return token.Position; } private TextPosition FillDeclarations(CssDeclarationRule rule, Func<string, CssProperty> createProperty) { CssToken token = NextToken(); CollectTrivia(ref token); while (token.IsNot(CssTokenType.EndOfFile, CssTokenType.CurlyBracketClose)) { CssProperty cssProperty = CreateDeclarationWith(createProperty, ref token); if (cssProperty != null && cssProperty.HasValue) rule.SetProperty(cssProperty); CollectTrivia(ref token); } return token.Position; } private TextPosition FillRules(CssGroupingRule group) { CssToken token = NextToken(); CollectTrivia(ref token); while (token.IsNot(CssTokenType.EndOfFile, CssTokenType.CurlyBracketClose)) { CssRule rule = CreateRule(token); token = NextToken(); CollectTrivia(ref token); group.Rules.Add(rule); } return token.Position; } private void FillMediaList(MediaList list, CssTokenType end, ref CssToken token) { _nodes.Push(list); if (token.Type != end) { while (token.Type != CssTokenType.EndOfFile) { CssMedium cssMedium = CreateMedium(ref token); if (cssMedium != null) list.AppendChild(cssMedium); if (token.Type != CssTokenType.Comma) break; token = NextToken(); CollectTrivia(ref token); } if (token.Type != end || list.Length == 0) { list.Clear(); list.AppendChild(new CssMedium { IsInverse = true, Type = Keywords.All }); } } _nodes.Pop(); } private ISelector CreateSelector(ref CssToken token) { CssSelectorConstructor selectorCreator = _parser.GetSelectorCreator(); TextPosition position = token.Position; while (token.IsNot(CssTokenType.EndOfFile, CssTokenType.CurlyBracketOpen, CssTokenType.CurlyBracketClose)) { selectorCreator.Apply(token); token = NextToken(); } bool isValid = selectorCreator.IsValid; ISelector selector = selectorCreator.ToPool(); CssNode cssNode = selector as CssNode; if (cssNode != null) { TextPosition end = token.Position.Shift(-1); cssNode.SourceCode = CreateView(position, end); } if (!isValid && !_parser.Options.IsToleratingInvalidValues) { RaiseErrorOccurred(CssParseError.InvalidSelector, position); selector = null; } return selector; } private CssValue CreateValue(CssTokenType closing, ref CssToken token, out bool important) { CssValueBuilder cssValueBuilder = Pool.NewValueBuilder(); _tokenizer.IsInValue = true; token = NextToken(); TextPosition position = token.Position; while (token.IsNot(CssTokenType.EndOfFile, CssTokenType.Semicolon, closing)) { cssValueBuilder.Apply(token); token = NextToken(); } important = cssValueBuilder.IsImportant; _tokenizer.IsInValue = false; bool isValid = cssValueBuilder.IsValid; CssValue cssValue = cssValueBuilder.ToPool(); CssNode cssNode = cssValue; if (cssNode != null) { TextPosition end = token.Position.Shift(-1); cssNode.SourceCode = CreateView(position, end); } if (!isValid && !_parser.Options.IsToleratingInvalidValues) { RaiseErrorOccurred(CssParseError.InvalidValue, position); cssValue = null; } return cssValue; } private string GetRuleName(ref CssToken token) { string result = string.Empty; if (token.Type == CssTokenType.Ident) { result = token.Data; token = NextToken(); } return result; } private MediaFeature CreateFeature(ref CssToken token) { if (token.Type == CssTokenType.Ident) { TextPosition position = token.Position; CssValue value = CssValue.Empty; MediaFeature mediaFeature = _parser.Options.IsToleratingInvalidConstraints ? new UnknownMediaFeature(token.Data) : Factory.MediaFeatures.Create(token.Data); token = NextToken(); if (token.Type == CssTokenType.Colon) { CssValueBuilder cssValueBuilder = Pool.NewValueBuilder(); token = NextToken(); while (token.IsNot(CssTokenType.RoundBracketClose, CssTokenType.EndOfFile) || !cssValueBuilder.IsReady) { cssValueBuilder.Apply(token); token = NextToken(); } value = cssValueBuilder.ToPool(); } else if (token.Type == CssTokenType.EndOfFile) { return null; } if (mediaFeature != null && mediaFeature.TrySetValue(value)) { CssNode cssNode = mediaFeature; if (cssNode != null) { TextPosition end = token.Position.Shift(-1); cssNode.SourceCode = CreateView(position, end); } return mediaFeature; } } else JumpToArgEnd(ref token); return null; } } }