CssBuilder
See http://dev.w3.org/csswg/css-syntax/#parsing for details.
using AngleSharp.Css;
using AngleSharp.Css.Conditions;
using AngleSharp.Css.MediaFeatures;
using AngleSharp.Css.Values;
using AngleSharp.Dom;
using AngleSharp.Dom.Collections;
using AngleSharp.Dom.Css;
using AngleSharp.Extensions;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
namespace AngleSharp.Parser.Css
{
[DebuggerStepThrough]
internal sealed class CssBuilder
{
private readonly CssTokenizer _tokenizer;
private readonly CssParser _parser;
private readonly Stack<CssNode> _nodes;
public CssNode Container {
get {
if (_nodes.Count <= 0)
return null;
return _nodes.Peek();
}
}
public CssBuilder(CssTokenizer tokenizer, CssParser parser)
{
_tokenizer = tokenizer;
_parser = parser;
_nodes = new Stack<CssNode>();
if (parser.Options.IsStoringTrivia)
_nodes.Push(new 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);
SkipRule(token);
return null;
case CssTokenType.String:
case CssTokenType.Url:
case CssTokenType.RoundBracketClose:
case CssTokenType.CurlyBracketClose:
case CssTokenType.SquareBracketClose:
RaiseErrorOccurred(CssParseError.InvalidToken, token);
SkipRule(token);
return null;
default:
return CreateStyle(token);
}
}
public CssRule CreateCharset(CssToken current)
{
CssCharsetRule cssCharsetRule = new CssCharsetRule(_parser);
CssToken token = NextToken();
CollectTrivia(ref token);
if (token.Type == CssTokenType.String)
cssCharsetRule.CharacterSet = token.Data;
JumpToEnd(token);
return cssCharsetRule;
}
public CssRule CreateDocument(CssToken current)
{
CssDocumentRule cssDocumentRule = new CssDocumentRule(_parser);
CssToken token = NextToken();
CollectTrivia(ref token);
FillFunctions(cssDocumentRule.Conditions, ref token);
CollectTrivia(ref token);
if (token.Type != CssTokenType.CurlyBracketOpen)
return SkipDeclarations(token);
FillRules(cssDocumentRule);
return cssDocumentRule;
}
public CssRule CreateViewport(CssToken current)
{
CssViewportRule cssViewportRule = new CssViewportRule(_parser);
CssToken token = NextToken();
CollectTrivia(ref token);
if (token.Type != CssTokenType.CurlyBracketOpen)
return SkipDeclarations(token);
FillDeclarations(cssViewportRule, Factory.Properties.CreateViewport);
return cssViewportRule;
}
public CssRule CreateFontFace(CssToken current)
{
CssFontFaceRule cssFontFaceRule = new CssFontFaceRule(_parser);
CssToken token = NextToken();
CollectTrivia(ref token);
if (token.Type != CssTokenType.CurlyBracketOpen)
return SkipDeclarations(token);
FillDeclarations(cssFontFaceRule, Factory.Properties.CreateFont);
return cssFontFaceRule;
}
public CssRule CreateImport(CssToken current)
{
CssImportRule cssImportRule = new CssImportRule(_parser);
CssToken token = NextToken();
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(token);
return cssImportRule;
}
public CssRule CreateKeyframes(CssToken current)
{
CssKeyframesRule cssKeyframesRule = new CssKeyframesRule(_parser);
CssToken token = NextToken();
CollectTrivia(ref token);
cssKeyframesRule.Name = GetRuleName(ref token);
CollectTrivia(ref token);
if (token.Type != CssTokenType.CurlyBracketOpen)
return SkipDeclarations(token);
FillKeyframeRules(cssKeyframesRule);
return cssKeyframesRule;
}
public CssRule CreateMedia(CssToken current)
{
CssMediaRule cssMediaRule = new CssMediaRule(_parser);
CssToken token = NextToken();
CollectTrivia(ref token);
FillMediaList(cssMediaRule.Media, CssTokenType.CurlyBracketOpen, ref token);
CollectTrivia(ref token);
if (token.Type != CssTokenType.CurlyBracketOpen) {
while (token.Type != CssTokenType.Eof) {
if (token.Type == CssTokenType.Semicolon)
return null;
if (token.Type == CssTokenType.CurlyBracketOpen)
break;
token = NextToken();
}
}
FillRules(cssMediaRule);
return cssMediaRule;
}
public CssRule CreateNamespace(CssToken current)
{
CssNamespaceRule cssNamespaceRule = new CssNamespaceRule(_parser);
CssToken token = NextToken();
CollectTrivia(ref token);
cssNamespaceRule.Prefix = GetRuleName(ref token);
CollectTrivia(ref token);
if (token.Type == CssTokenType.Url)
cssNamespaceRule.NamespaceUri = token.Data;
JumpToEnd(token);
return cssNamespaceRule;
}
public CssRule CreatePage(CssToken current)
{
CssPageRule cssPageRule = new CssPageRule(_parser);
CssToken token = NextToken();
CollectTrivia(ref token);
cssPageRule.Selector = CreateSelector(ref token);
CollectTrivia(ref token);
if (token.Type != CssTokenType.CurlyBracketOpen)
return SkipDeclarations(token);
FillDeclarations(cssPageRule.Style);
return cssPageRule;
}
public CssRule CreateSupports(CssToken current)
{
CssSupportsRule cssSupportsRule = new CssSupportsRule(_parser);
CssToken token = NextToken();
CollectTrivia(ref token);
cssSupportsRule.Condition = AggregateCondition(ref token);
CollectTrivia(ref token);
if (token.Type != CssTokenType.CurlyBracketOpen)
return SkipDeclarations(token);
FillRules(cssSupportsRule);
return cssSupportsRule;
}
public CssRule CreateStyle(CssToken current)
{
CssStyleRule cssStyleRule = new CssStyleRule(_parser);
CollectTrivia(ref current);
cssStyleRule.Selector = CreateSelector(ref current);
FillDeclarations(cssStyleRule.Style);
if (cssStyleRule.Selector == null)
return null;
return cssStyleRule;
}
public CssKeyframeRule CreateKeyframeRule(CssToken current)
{
CssKeyframeRule cssKeyframeRule = new CssKeyframeRule(_parser);
CollectTrivia(ref current);
cssKeyframeRule.Key = CreateKeyframeSelector(ref current);
CollectTrivia(ref current);
FillDeclarations(cssKeyframeRule.Style);
return cssKeyframeRule;
}
public CssRule CreateUnknown(CssToken current)
{
CssUnknownRule cssUnknownRule = null;
if (_parser.Options.IsIncludingUnknownRules) {
CssToken cssToken = NextToken();
cssUnknownRule = new CssUnknownRule(current.Data, _parser);
while (cssToken.IsNot(CssTokenType.CurlyBracketOpen, CssTokenType.Semicolon, CssTokenType.Eof)) {
cssUnknownRule.Prelude.Add(cssToken);
cssToken = NextToken();
}
if (cssToken.Type != CssTokenType.Eof) {
cssUnknownRule.Content.Add(cssToken);
if (cssToken.Type == CssTokenType.CurlyBracketOpen) {
int num = 1;
do {
cssToken = NextToken();
cssUnknownRule.Content.Add(cssToken);
switch (cssToken.Type) {
case CssTokenType.CurlyBracketOpen:
num++;
break;
case CssTokenType.CurlyBracketClose:
num--;
break;
case CssTokenType.Eof:
num = 0;
break;
}
} while (num != 0);
}
}
} else {
RaiseErrorOccurred(CssParseError.UnknownAtRule, current);
SkipRule(current);
}
return cssUnknownRule;
}
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.Eof) {
CreateNewNode();
CssMedium cssMedium = CreateMedium(ref token);
if (cssMedium == null || token.IsNot(CssTokenType.Comma, CssTokenType.Eof))
throw new DomException(DomError.Syntax);
token = NextToken();
CollectTrivia(ref token);
list.Add(CloseNode(cssMedium));
}
return list;
}
public void CreateRules(CssStyleSheet sheet)
{
CssToken token = NextToken();
CollectTrivia(ref token);
while (token.Type != CssTokenType.Eof) {
CreateNewNode();
CssRule entity = CreateRule(token);
token = NextToken();
CollectTrivia(ref token);
sheet.AddRule(CloseNode(entity));
}
}
public CssCondition 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;
CssToken token2 = token;
CreateNewNode();
CollectTrivia(ref token);
while (token.Type != CssTokenType.Eof) {
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, token2);
return CloseNode(new KeyframeSelector(list));
}
public List<CssDocumentFunction> CreateFunctions(ref CssToken token)
{
List<CssDocumentFunction> list = new List<CssDocumentFunction>();
CollectTrivia(ref token);
FillFunctions(list, ref token);
return list;
}
public void FillDeclarations(CssStyleDeclaration style)
{
CssToken token = NextToken();
CollectTrivia(ref token);
while (token.IsNot(CssTokenType.Eof, CssTokenType.CurlyBracketClose)) {
CssProperty cssProperty = CreateDeclarationWith(Factory.Properties.Create, ref token);
if (cssProperty != null && cssProperty.HasValue)
style.SetProperty(cssProperty);
CollectTrivia(ref token);
}
}
public CssProperty CreateDeclarationWith(Func<string, CssProperty> createProperty, ref CssToken token)
{
CssProperty cssProperty = null;
CreateNewNode();
StringBuilder stringBuilder = Pool.NewStringBuilder();
while (token.Type != CssTokenType.Eof && token.Type != CssTokenType.Colon && token.Type != CssTokenType.Whitespace && token.Type != CssTokenType.Comment && token.Type != CssTokenType.CurlyBracketOpen && token.Type != CssTokenType.Semicolon) {
stringBuilder.Append(token.ToValue());
token = NextToken();
}
string text = stringBuilder.ToPool();
if (text.Length > 0) {
cssProperty = ((_parser.Options.IsIncludingUnknownDeclarations || _parser.Options.IsToleratingInvalidValues) ? new CssUnknownProperty(text) : createProperty(text));
if (cssProperty == null)
RaiseErrorOccurred(CssParseError.UnknownDeclarationName, token);
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);
else if (cssProperty != null && cssProperty.TrySetValue(cssValue)) {
cssProperty.IsImportant = important;
}
CollectTrivia(ref token);
} else
RaiseErrorOccurred(CssParseError.ColonMissing, token);
JumpToDeclEnd(ref token);
} else if (token.Type != CssTokenType.Eof) {
RaiseErrorOccurred(CssParseError.IdentExpected, token);
JumpToDeclEnd(ref token);
}
if (token.Type == CssTokenType.Semicolon)
token = NextToken();
return CloseNode(cssProperty);
}
public CssProperty CreateDeclaration(ref CssToken token)
{
CollectTrivia(ref token);
return CreateDeclarationWith(Factory.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);
CreateNewNode();
MediaFeature mediaFeature = CloseNode(CreateFeature(ref token));
if (mediaFeature != null)
cssMedium.AddConstraint(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.Eof);
return cssMedium;
}
private void SkipRule(CssToken current)
{
int num = 0;
while (current.Type != CssTokenType.Eof) {
if (current.Type == CssTokenType.CurlyBracketOpen)
num++;
else if (current.Type == CssTokenType.CurlyBracketClose) {
num--;
}
if (num <= 0 && current.Is(CssTokenType.Semicolon, CssTokenType.CurlyBracketClose))
break;
current = NextToken();
}
}
private void JumpToEnd(CssToken current)
{
while (current.IsNot(CssTokenType.Eof, CssTokenType.Semicolon)) {
current = NextToken();
}
}
private void JumpToArgEnd(ref CssToken current)
{
int num = 0;
while (current.Type != CssTokenType.Eof) {
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.Eof) {
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()
{
CssToken cssToken = _tokenizer.Get();
if (_nodes.Count > 0)
_nodes.Peek().Tokens.Add(cssToken);
return cssToken;
}
private CssNode CreateNewNode()
{
CssNode cssNode = null;
if (_parser.Options.IsStoringTrivia) {
List<CssToken> tokens = _nodes.Peek().Tokens;
cssNode = new CssNode();
if (tokens.Count > 0) {
cssNode.Tokens.Add(tokens[tokens.Count - 1]);
tokens.RemoveAt(tokens.Count - 1);
}
_nodes.Peek().Children.Add(cssNode);
_nodes.Push(cssNode);
}
return cssNode;
}
private T CloseNode<T>(T entity) where T : IStyleFormattable
{
if (_nodes.Count > 0) {
CssNode cssNode = _nodes.Pop();
List<CssToken> tokens = cssNode.Tokens;
cssNode.Entity = (IStyleFormattable)(object)entity;
if (tokens.Count > 0) {
_nodes.Peek().Tokens.Add(tokens[tokens.Count - 1]);
tokens.RemoveAt(tokens.Count - 1);
}
}
return entity;
}
private void CollectTrivia(ref CssToken token)
{
if (_nodes.Count > 0)
StoreTrivia(ref token);
else
RemoveTrivia(ref token);
}
private void StoreTrivia(ref CssToken token)
{
List<CssToken> tokens = _nodes.Peek().Tokens;
while (token.Type == CssTokenType.Whitespace || token.Type == CssTokenType.Comment) {
token = _tokenizer.Get();
tokens.Add(token);
}
}
private void RemoveTrivia(ref CssToken token)
{
while (token.Type == CssTokenType.Whitespace || token.Type == CssTokenType.Comment) {
token = _tokenizer.Get();
}
}
private CssRule SkipDeclarations(CssToken token)
{
RaiseErrorOccurred(CssParseError.InvalidToken, token);
SkipRule(token);
return null;
}
private void RaiseErrorOccurred(CssParseError code, CssToken token)
{
_tokenizer.RaiseErrorOccurred(code, token.Position);
}
private CssCondition AggregateCondition(ref CssToken token)
{
CssCondition cssCondition = ExtractCondition(ref token);
if (cssCondition != null) {
CollectTrivia(ref token);
string data = token.Data;
Func<IEnumerable<CssCondition>, CssCondition> creator = data.GetCreator();
if (creator != null) {
token = NextToken();
CollectTrivia(ref token);
CreateNewNode();
List<CssCondition> arg = MultipleConditions(cssCondition, data, ref token);
cssCondition = CloseNode(creator(arg));
}
}
return cssCondition;
}
private CssCondition ExtractCondition(ref CssToken token)
{
CssCondition cssCondition = null;
CreateNewNode();
if (token.Type == CssTokenType.RoundBracketOpen) {
token = NextToken();
CollectTrivia(ref token);
cssCondition = AggregateCondition(ref token);
if (cssCondition != null)
cssCondition = new GroupCondition(cssCondition);
else if (token.Type == CssTokenType.Ident) {
cssCondition = DeclarationCondition(ref token);
}
if (token.Type == CssTokenType.RoundBracketClose) {
token = NextToken();
CollectTrivia(ref token);
}
} else if (token.Data.Isi(Keywords.Not)) {
token = NextToken();
CollectTrivia(ref token);
cssCondition = ExtractCondition(ref token);
if (cssCondition != null)
cssCondition = new NotCondition(cssCondition);
}
return CloseNode(cssCondition);
}
private CssCondition DeclarationCondition(ref CssToken token)
{
CssProperty cssProperty = Factory.Properties.Create(token.Data) ?? new CssUnknownProperty(token.Data);
DeclarationCondition entity = null;
CreateNewNode();
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)
entity = new DeclarationCondition(cssProperty, cssValue);
}
return CloseNode(entity);
}
private List<CssCondition> MultipleConditions(CssCondition condition, string connector, ref CssToken token)
{
List<CssCondition> list = new List<CssCondition>();
CollectTrivia(ref token);
list.Add(condition);
while (token.Type != CssTokenType.Eof) {
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(List<CssDocumentFunction> functions, ref CssToken token)
{
do {
CreateNewNode();
CssDocumentFunction cssDocumentFunction = token.ToDocumentFunction();
if (cssDocumentFunction == null)
break;
token = NextToken();
CollectTrivia(ref token);
functions.Add(CloseNode(cssDocumentFunction));
if (token.Type != CssTokenType.Comma)
break;
token = NextToken();
CollectTrivia(ref token);
} while (token.Type == CssTokenType.Eof);
}
private void FillKeyframeRules(CssKeyframesRule parentRule)
{
CssToken token = NextToken();
CollectTrivia(ref token);
while (token.IsNot(CssTokenType.Eof, CssTokenType.CurlyBracketClose)) {
CreateNewNode();
CssKeyframeRule entity = CreateKeyframeRule(token);
token = NextToken();
CollectTrivia(ref token);
parentRule.AddRule(CloseNode(entity));
}
}
private void FillDeclarations(CssDeclarationRule rule, Func<string, CssProperty> createProperty)
{
CssToken token = NextToken();
CollectTrivia(ref token);
while (token.IsNot(CssTokenType.Eof, CssTokenType.CurlyBracketClose)) {
CssProperty cssProperty = CreateDeclarationWith(createProperty, ref token);
if (cssProperty != null && cssProperty.HasValue)
rule.SetProperty(cssProperty);
CollectTrivia(ref token);
}
}
private void FillRules(CssGroupingRule group)
{
CssToken token = NextToken();
CollectTrivia(ref token);
while (token.IsNot(CssTokenType.Eof, CssTokenType.CurlyBracketClose)) {
CreateNewNode();
CssRule entity = CreateRule(token);
token = NextToken();
CollectTrivia(ref token);
group.AddRule(CloseNode(entity));
}
}
private void FillMediaList(MediaList list, CssTokenType end, ref CssToken token)
{
if (token.Type != end) {
while (token.Type != CssTokenType.Eof) {
CreateNewNode();
CssMedium cssMedium = CloseNode(CreateMedium(ref token));
if (cssMedium != null)
list.Add(cssMedium);
if (token.Type != CssTokenType.Comma)
break;
token = NextToken();
CollectTrivia(ref token);
}
if (token.Type != end || list.Length <= 0) {
list.Clear();
list.Add(new CssMedium {
IsInverse = true,
Type = Keywords.All
});
}
}
}
private ISelector CreateSelector(ref CssToken token)
{
CssSelectorConstructor cssSelectorConstructor = Pool.NewSelectorConstructor();
CssToken token2 = token;
CreateNewNode();
while (token.IsNot(CssTokenType.Eof, CssTokenType.CurlyBracketOpen, CssTokenType.CurlyBracketClose)) {
cssSelectorConstructor.Apply(token);
token = NextToken();
}
ISelector entity = cssSelectorConstructor.ToPool();
if (!cssSelectorConstructor.IsValid && !_parser.Options.IsToleratingInvalidValues) {
RaiseErrorOccurred(CssParseError.InvalidSelector, token2);
entity = null;
}
return CloseNode(entity);
}
private CssValue CreateValue(CssTokenType closing, ref CssToken token, out bool important)
{
CssValueBuilder cssValueBuilder = Pool.NewValueBuilder();
_tokenizer.IsInValue = true;
token = NextToken();
CssToken token2 = token;
CreateNewNode();
while (token.Type != CssTokenType.Eof && !token.Is(CssTokenType.Semicolon, closing)) {
cssValueBuilder.Apply(token);
token = NextToken();
}
important = cssValueBuilder.IsImportant;
_tokenizer.IsInValue = false;
CssValue entity = cssValueBuilder.ToPool();
if (!cssValueBuilder.IsValid && !_parser.Options.IsToleratingInvalidValues) {
RaiseErrorOccurred(CssParseError.InvalidValue, token2);
entity = null;
}
return CloseNode(entity);
}
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) {
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.Type != CssTokenType.RoundBracketClose || !cssValueBuilder.IsReady) && token.Type != CssTokenType.Eof) {
cssValueBuilder.Apply(token);
token = NextToken();
}
value = cssValueBuilder.ToPool();
} else if (token.Type == CssTokenType.Eof) {
return null;
}
if (mediaFeature != null && mediaFeature.TrySetValue(value))
return mediaFeature;
} else
JumpToArgEnd(ref token);
return null;
}
}
}