AngleSharp by Florian Rappl

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

 CssParser

public sealed class CssParser : IParser
The CSS parser. See http://dev.w3.org/csswg/css-syntax/#parsing for more details.
using AngleSharp.DOM; using AngleSharp.DOM.Collections; using AngleSharp.DOM.Css; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; using System.Threading.Tasks; namespace AngleSharp.Parser.Css { [DebuggerStepThrough] public sealed class CssParser : IParser { private enum CssState { Data, InSelector, InDeclaration, AfterProperty, BeforeValue, InValuePool, InValueList, InSingleValue, InMediaList, InMediaValue, BeforeImport, BeforeCharset, BeforeNamespacePrefix, AfterNamespacePrefix, AfterInstruction, InCondition, BeforeKeyframesName, BeforeKeyframesData, KeyframesData, InKeyframeText, BeforeDocumentFunction, InDocumentFunction, AfterDocumentFunction, BetweenDocumentFunctions, InUnknown, ValueImportant, AfterValue, InHexValue, InFunction } private CssSelectorConstructor selector; private CssValueBuilder value; private bool skipExceptions; private CssTokenizer tokenizer; private CSSProperty property; private bool started; private bool quirks; private CSSStyleSheet sheet; private Stack<CSSRule> open; private StringBuilder buffer; private CssState state; private object sync; private Task task; public bool IsAsync => task != null; public CSSStyleSheet Result { get { Parse(); return sheet; } } public bool IsQuirksMode => quirks; internal CSSRule CurrentRule { get { if (open.Count <= 0) return null; return open.Peek(); } } public event EventHandler<ParseErrorEventArgs> ParseError; public CssParser(string source, IConfiguration configuration = null) : this(new CSSStyleSheet(), new SourceManager(source, configuration)) { } public CssParser(Stream stream, IConfiguration configuration = null) : this(new CSSStyleSheet(), new SourceManager(stream, configuration)) { } public CssParser(CSSStyleSheet stylesheet, string source) : this(stylesheet, new SourceManager(source, stylesheet.Options)) { } public CssParser(CSSStyleSheet stylesheet, Stream stream) : this(stylesheet, new SourceManager(stream, stylesheet.Options)) { } internal CssParser(CSSStyleSheet stylesheet, SourceManager source) { selector = Pool.NewSelectorConstructor(); value = new CssValueBuilder(); sync = new object(); skipExceptions = true; tokenizer = new CssTokenizer(source); CssTokenizer cssTokenizer = tokenizer; EventHandler<ParseErrorEventArgs> eventHandler = delegate(object s, ParseErrorEventArgs ev) { if (this.ParseError != null) this.ParseError(this, ev); }; cssTokenizer.ErrorOccurred += eventHandler; quirks = stylesheet.Options.UseQuirksMode; started = false; sheet = stylesheet; open = new Stack<CSSRule>(); SwitchTo(CssState.Data); } public Task ParseAsync() { lock (sync) { if (!started) { started = true; task = Task.Factory.StartNew(delegate { Kernel(); }); } else if (task == null) { throw new InvalidOperationException("The parser has already run synchronously."); } return task; } } public void Parse() { bool flag = false; lock (sync) { if (!started) { started = true; flag = true; } } if (flag) Kernel(); } private bool Data(CssToken token) { if (token.Type == CssTokenType.AtKeyword) { switch (((CssKeywordToken)token).Data) { case "media": AddRule(new CSSMediaRule()); SwitchTo(CssState.InMediaList); break; case "page": AddRule(new CSSPageRule()); SwitchTo(CssState.InSelector); break; case "import": AddRule(new CSSImportRule()); SwitchTo(CssState.BeforeImport); break; case "font-face": AddRule(new CSSFontFaceRule()); SwitchTo(CssState.InDeclaration); break; case "charset": AddRule(new CSSCharsetRule()); SwitchTo(CssState.BeforeCharset); break; case "namespace": AddRule(new CSSNamespaceRule()); SwitchTo(CssState.BeforeNamespacePrefix); break; case "supports": buffer = Pool.NewStringBuilder(); AddRule(new CSSSupportsRule()); SwitchTo(CssState.InCondition); break; case "keyframes": AddRule(new CSSKeyframesRule()); SwitchTo(CssState.BeforeKeyframesName); break; case "document": AddRule(new CSSDocumentRule()); SwitchTo(CssState.BeforeDocumentFunction); break; default: buffer = Pool.NewStringBuilder(); AddRule(new CSSUnknownRule()); SwitchTo(CssState.InUnknown); InUnknown(token); break; } return true; } if (token.Type == CssTokenType.CurlyBracketClose) return CloseRule(); AddRule(new CSSStyleRule()); SwitchTo(CssState.InSelector); InSelector(token); return true; } private bool InUnknown(CssToken token) { switch (token.Type) { case CssTokenType.Semicolon: CurrentRuleAs<CSSUnknownRule>().SetInstruction(buffer.ToPool()); SwitchTo(CssState.Data); return CloseRule(); case CssTokenType.CurlyBracketOpen: CurrentRuleAs<CSSUnknownRule>().SetCondition(buffer.ToPool()); SwitchTo(CssState.Data); break; default: buffer.Append(token.ToValue()); break; } return true; } private bool InSelector(CssToken token) { if (token.Type == CssTokenType.CurlyBracketOpen) { ICssSelector cssSelector = CurrentRule as ICssSelector; if (cssSelector != null) cssSelector.Selector = selector.Result; SwitchTo((CurrentRule is CSSStyleRule) ? CssState.InDeclaration : CssState.Data); } else { if (token.Type == CssTokenType.CurlyBracketClose) return false; selector.Apply(token); } return true; } private bool InDeclaration(CssToken token) { if (token.Type == CssTokenType.CurlyBracketClose) { CloseProperty(); SwitchTo((CurrentRule is CSSKeyframeRule) ? CssState.KeyframesData : CssState.Data); return CloseRule(); } if (token.Type == CssTokenType.Ident) { AddDeclaration(((CssKeywordToken)token).Data); SwitchTo(CssState.AfterProperty); return true; } return false; } private bool AfterInstruction(CssToken token) { if (token.Type == CssTokenType.Semicolon) { SwitchTo(CssState.Data); return CloseRule(); } return false; } private bool InCondition(CssToken token) { CssTokenType type = token.Type; if (type == CssTokenType.CurlyBracketOpen) { CurrentRuleAs<CSSSupportsRule>().ConditionText = buffer.ToPool(); SwitchTo(CssState.Data); } else buffer.Append(token.ToValue()); return true; } private bool BeforePrefix(CssToken token) { if (token.Type == CssTokenType.Ident) { CurrentRuleAs<CSSNamespaceRule>().Prefix = ((CssKeywordToken)token).Data; SwitchTo(CssState.AfterNamespacePrefix); return true; } SwitchTo(CssState.AfterInstruction); return AfterInstruction(token); } private bool BeforeNamespace(CssToken token) { SwitchTo(CssState.AfterInstruction); if (token.Type == CssTokenType.String) { CurrentRuleAs<CSSNamespaceRule>().NamespaceURI = ((CssStringToken)token).Data; return true; } return AfterInstruction(token); } private bool BeforeCharset(CssToken token) { SwitchTo(CssState.AfterInstruction); if (token.Type == CssTokenType.String) { CurrentRuleAs<CSSCharsetRule>().Encoding = ((CssStringToken)token).Data; return true; } return AfterInstruction(token); } private bool BeforeImport(CssToken token) { if (token.Type == CssTokenType.String || token.Type == CssTokenType.Url) { CurrentRuleAs<CSSImportRule>().Href = ((CssStringToken)token).Data; SwitchTo(CssState.InMediaList); return true; } SwitchTo(CssState.AfterInstruction); return false; } private bool AfterProperty(CssToken token) { if (token.Type == CssTokenType.Colon) { value.Reset(); SwitchTo(CssState.BeforeValue); return true; } if (token.Type == CssTokenType.Semicolon || token.Type == CssTokenType.CurlyBracketClose) AfterValue(token); return false; } private bool BeforeValue(CssToken token) { if (token.Type == CssTokenType.Semicolon) SwitchTo(CssState.InDeclaration); else { if (token.Type != CssTokenType.CurlyBracketClose) { SwitchTo(CssState.InSingleValue); return InSingleValue(token); } InDeclaration(token); } return false; } private bool InSingleValue(CssToken token) { switch (token.Type) { case CssTokenType.Percentage: case CssTokenType.Dimension: value.AddValue(ToUnit((CssUnitToken)token)); return true; case CssTokenType.Hash: return InSingleValueHexColor(((CssKeywordToken)token).Data); case CssTokenType.Delim: return InSingleValueDelim((CssDelimToken)token); case CssTokenType.Ident: return InSingleValueIdent((CssKeywordToken)token); case CssTokenType.String: value.AddValue(new CSSStringValue(((CssStringToken)token).Data)); return true; case CssTokenType.Url: value.AddValue(new CSSPrimitiveValue<Location>(new Location(((CssStringToken)token).Data))); return true; case CssTokenType.Number: value.AddValue(ToNumber((CssNumberToken)token)); return true; case CssTokenType.Whitespace: SwitchTo(CssState.InValueList); return true; case CssTokenType.Function: value.AddFunction(((CssKeywordToken)token).Data); SwitchTo(CssState.InFunction); return true; case CssTokenType.Comma: SwitchTo(CssState.InValuePool); return true; case CssTokenType.CurlyBracketClose: case CssTokenType.Semicolon: return AfterValue(token); default: return false; } } private bool InValueFunction(CssToken token) { switch (token.Type) { case CssTokenType.RoundBracketClose: if (value.CloseFunction()) SwitchTo(CssState.InSingleValue); return true; case CssTokenType.Comma: value.NextArgument(); return true; default: return InSingleValue(token); } } private bool InValueList(CssToken token) { if (token.Type == CssTokenType.Semicolon || token.Type == CssTokenType.CurlyBracketClose) AfterValue(token); else { if (token.Type != CssTokenType.Comma) { SwitchTo(CssState.InSingleValue); return InSingleValue(token); } SwitchTo(CssState.InValuePool); } return true; } private bool InValuePool(CssToken token) { if (token.Type != CssTokenType.Semicolon && token.Type != CssTokenType.CurlyBracketClose) { value.NextArgument(); SwitchTo(CssState.InSingleValue); return InSingleValue(token); } AfterValue(token); return false; } private bool InHexValue(CssToken token) { switch (token.Type) { case CssTokenType.Ident: case CssTokenType.Number: case CssTokenType.Dimension: { string text = token.ToValue(); if (buffer.Length + text.Length <= 6) { buffer.Append(text); return true; } break; } } buffer.ToPool(); InSingleValueHexColor(buffer.ToString()); SwitchTo(CssState.InSingleValue); return InSingleValue(token); } private bool AfterValue(CssToken token) { if (token.Type == CssTokenType.Semicolon) { CloseProperty(); SwitchTo(CssState.InDeclaration); return true; } if (token.Type == CssTokenType.CurlyBracketClose) return InDeclaration(token); return false; } private bool ValueImportant(CssToken token) { if (token.Type == CssTokenType.Ident && ((CssKeywordToken)token).Data == "important") { SwitchTo(CssState.AfterValue); property.Important = true; return true; } return AfterValue(token); } private bool BeforeKeyframesName(CssToken token) { SwitchTo(CssState.BeforeKeyframesData); if (token.Type == CssTokenType.Ident) { CurrentRuleAs<CSSKeyframesRule>().Name = ((CssKeywordToken)token).Data; return true; } if (token.Type == CssTokenType.CurlyBracketOpen) SwitchTo(CssState.KeyframesData); return false; } private bool BeforeKeyframesData(CssToken token) { if (token.Type == CssTokenType.CurlyBracketOpen) { SwitchTo(CssState.BeforeKeyframesData); return true; } return false; } private bool KeyframesData(CssToken token) { if (token.Type == CssTokenType.CurlyBracketClose) { SwitchTo(CssState.Data); return CloseRule(); } buffer = Pool.NewStringBuilder(); return InKeyframeText(token); } private bool InKeyframeText(CssToken token) { if (token.Type == CssTokenType.CurlyBracketOpen) { CSSKeyframeRule cSSKeyframeRule = new CSSKeyframeRule(); cSSKeyframeRule.KeyText = buffer.ToPool(); AddRule(cSSKeyframeRule); SwitchTo(CssState.InDeclaration); return true; } if (token.Type == CssTokenType.CurlyBracketClose) { buffer.ToPool(); KeyframesData(token); return false; } buffer.Append(token.ToValue()); return true; } private bool BeforeDocumentFunction(CssToken token) { switch (token.Type) { case CssTokenType.Url: CurrentRuleAs<CSSDocumentRule>().Conditions.Add(Tuple.Create(CSSDocumentRule.DocumentFunction.Url, ((CssStringToken)token).Data)); break; case CssTokenType.UrlPrefix: CurrentRuleAs<CSSDocumentRule>().Conditions.Add(Tuple.Create(CSSDocumentRule.DocumentFunction.UrlPrefix, ((CssStringToken)token).Data)); break; case CssTokenType.Domain: CurrentRuleAs<CSSDocumentRule>().Conditions.Add(Tuple.Create(CSSDocumentRule.DocumentFunction.Domain, ((CssStringToken)token).Data)); break; case CssTokenType.Function: if (string.Compare(((CssKeywordToken)token).Data, "regexp", StringComparison.OrdinalIgnoreCase) == 0) { SwitchTo(CssState.InDocumentFunction); return true; } SwitchTo(CssState.AfterDocumentFunction); return false; default: SwitchTo(CssState.Data); return false; } SwitchTo(CssState.BetweenDocumentFunctions); return true; } private bool InDocumentFunction(CssToken token) { SwitchTo(CssState.AfterDocumentFunction); if (token.Type == CssTokenType.String) { CurrentRuleAs<CSSDocumentRule>().Conditions.Add(Tuple.Create(CSSDocumentRule.DocumentFunction.RegExp, ((CssStringToken)token).Data)); return true; } return false; } private bool AfterDocumentFunction(CssToken token) { SwitchTo(CssState.BetweenDocumentFunctions); return token.Type == CssTokenType.RoundBracketClose; } private bool BetweenDocumentFunctions(CssToken token) { if (token.Type == CssTokenType.Comma) { SwitchTo(CssState.BeforeDocumentFunction); return true; } if (token.Type == CssTokenType.CurlyBracketOpen) { SwitchTo(CssState.Data); return true; } SwitchTo(CssState.Data); return false; } private bool InMediaList(CssToken token) { if (token.Type == CssTokenType.Semicolon) { CloseRule(); SwitchTo(CssState.Data); return true; } buffer = Pool.NewStringBuilder(); SwitchTo(CssState.InMediaValue); return InMediaValue(token); } private bool InMediaValue(CssToken token) { switch (token.Type) { case CssTokenType.CurlyBracketOpen: case CssTokenType.Semicolon: { ICssMedia cssMedia = CurrentRule as ICssMedia; string newMedium = buffer.ToPool(); cssMedia?.Media.AppendMedium(newMedium); if (CurrentRule is CSSImportRule) return AfterInstruction(token); SwitchTo(CssState.Data); return token.Type == CssTokenType.CurlyBracketClose; } case CssTokenType.Comma: (CurrentRule as ICssMedia)?.Media.AppendMedium(buffer.ToString()); buffer.Clear(); return true; case CssTokenType.Whitespace: buffer.Append(' '); return true; default: buffer.Append(token.ToValue()); return true; } } private bool InSingleValueDelim(CssDelimToken token) { switch (token.Data) { case '!': SwitchTo(CssState.ValueImportant); return true; case '#': buffer = Pool.NewStringBuilder(); SwitchTo(CssState.InHexValue); return true; case '/': value.InsertDelimiter(); return true; default: return false; } } private bool InSingleValueIdent(CssKeywordToken token) { if (token.Data == "inherit") { property.Value = CSSValue.Inherit; SwitchTo(CssState.AfterValue); return true; } value.AddValue(new CSSIdentifierValue(token.Data)); return true; } private bool InSingleValueHexColor(string color) { if (Color.TryFromHex(color, out Color color2)) { value.AddValue(new CSSPrimitiveValue<Color>(color2)); return true; } return false; } private void CloseProperty() { if (property != null) { property.Value = value.ToValue(); property = null; } } private bool CloseRule() { if (open.Count > 0) { open.Pop(); return true; } return false; } private void AddRule(CSSRule rule) { rule.ParentStyleSheet = sheet; if (open.Count > 0) { ICssRules cssRules = open.Peek() as ICssRules; if (cssRules != null) { cssRules.CssRules.List.Add(rule); rule.ParentRule = open.Peek(); } } else sheet.CssRules.List.Add(rule); open.Push(rule); } private void AddDeclaration(string propertyName) { IStyleDeclaration styleDeclaration = CurrentRule as IStyleDeclaration; if (styleDeclaration != null) { property = CSSFactory.Create(propertyName, styleDeclaration.Style); styleDeclaration.Style.Set(property); } } private static CSSValue ToUnit(CssUnitToken token) { if (token.Type != CssTokenType.Percentage) { switch (token.Unit.ToLower()) { case "em": return new CSSPrimitiveValue<Length>(new Length(token.Data, Length.Unit.Em)); case "cm": return new CSSPrimitiveValue<Length>(new Length(token.Data, Length.Unit.Cm)); case "ex": return new CSSPrimitiveValue<Length>(new Length(token.Data, Length.Unit.Ex)); case "in": return new CSSPrimitiveValue<Length>(new Length(token.Data, Length.Unit.In)); case "mm": return new CSSPrimitiveValue<Length>(new Length(token.Data, Length.Unit.Mm)); case "pc": return new CSSPrimitiveValue<Length>(new Length(token.Data, Length.Unit.Pc)); case "pt": return new CSSPrimitiveValue<Length>(new Length(token.Data, Length.Unit.Pt)); case "px": return new CSSPrimitiveValue<Length>(new Length(token.Data, Length.Unit.Px)); case "rem": return new CSSPrimitiveValue<Length>(new Length(token.Data, Length.Unit.Rem)); case "ch": return new CSSPrimitiveValue<Length>(new Length(token.Data, Length.Unit.Ch)); case "vw": return new CSSPrimitiveValue<Length>(new Length(token.Data, Length.Unit.Vw)); case "vh": return new CSSPrimitiveValue<Length>(new Length(token.Data, Length.Unit.Vh)); case "vmin": return new CSSPrimitiveValue<Length>(new Length(token.Data, Length.Unit.Vmin)); case "vmax": return new CSSPrimitiveValue<Length>(new Length(token.Data, Length.Unit.Vmax)); case "ms": return new CSSPrimitiveValue<Time>(new Time(token.Data, Time.Unit.Ms)); case "s": return new CSSPrimitiveValue<Time>(new Time(token.Data, Time.Unit.S)); case "dpi": return new CSSPrimitiveValue<Resolution>(new Resolution(token.Data, Resolution.Unit.Dpi)); case "dpcm": return new CSSPrimitiveValue<Resolution>(new Resolution(token.Data, Resolution.Unit.Dpcm)); case "dppx": return new CSSPrimitiveValue<Resolution>(new Resolution(token.Data, Resolution.Unit.Dppx)); case "deg": return new CSSPrimitiveValue<Angle>(new Angle(token.Data, Angle.Unit.Deg)); case "grad": return new CSSPrimitiveValue<Angle>(new Angle(token.Data, Angle.Unit.Grad)); case "rad": return new CSSPrimitiveValue<Angle>(new Angle(token.Data, Angle.Unit.Rad)); case "turn": return new CSSPrimitiveValue<Angle>(new Angle(token.Data, Angle.Unit.Turn)); case "hz": return new CSSPrimitiveValue<Frequency>(new Frequency(token.Data, Frequency.Unit.Hz)); case "khz": return new CSSPrimitiveValue<Frequency>(new Frequency(token.Data, Frequency.Unit.Khz)); default: return new CSSPrimitiveValue<Number>(Number.Zero); } } return new CSSPrimitiveValue<Percent>(new Percent(token.Data)); } private static CSSValue ToNumber(CssNumberToken token) { if (token.Data == 0) return new CSSPrimitiveValue<Number>(Number.Zero); return new CSSPrimitiveValue<Number>(new Number(token.Data)); } private T CurrentRuleAs<T>() where T : CSSRule { if (open.Count > 0) return open.Peek() as T; return null; } private void SwitchTo(CssState newState) { switch (newState) { case CssState.InSelector: tokenizer.IgnoreComments = true; tokenizer.IgnoreWhitespace = false; selector.Reset(); selector.IgnoreErrors = skipExceptions; break; case CssState.InSingleValue: case CssState.InMediaValue: case CssState.InCondition: case CssState.InUnknown: case CssState.InHexValue: tokenizer.IgnoreComments = true; tokenizer.IgnoreWhitespace = false; break; default: tokenizer.IgnoreComments = true; tokenizer.IgnoreWhitespace = true; break; } state = newState; } private void Kernel() { IEnumerable<CssToken> tokens = tokenizer.Tokens; foreach (CssToken item in tokens) { if (!General(item)) RaiseErrorOccurred(ErrorCode.InputUnexpected); } if (property != null) General(CssSpecialCharacter.Semicolon); selector.ToPool(); } private bool General(CssToken token) { switch (state) { case CssState.Data: return Data(token); case CssState.InSelector: return InSelector(token); case CssState.InDeclaration: return InDeclaration(token); case CssState.AfterProperty: return AfterProperty(token); case CssState.BeforeValue: return BeforeValue(token); case CssState.InValuePool: return InValuePool(token); case CssState.InValueList: return InValueList(token); case CssState.InSingleValue: return InSingleValue(token); case CssState.ValueImportant: return ValueImportant(token); case CssState.AfterValue: return AfterValue(token); case CssState.InMediaList: return InMediaList(token); case CssState.InMediaValue: return InMediaValue(token); case CssState.BeforeImport: return BeforeImport(token); case CssState.AfterInstruction: return AfterInstruction(token); case CssState.BeforeCharset: return BeforeCharset(token); case CssState.BeforeNamespacePrefix: return BeforePrefix(token); case CssState.AfterNamespacePrefix: return BeforeNamespace(token); case CssState.InCondition: return InCondition(token); case CssState.InUnknown: return InUnknown(token); case CssState.InKeyframeText: return InKeyframeText(token); case CssState.BeforeDocumentFunction: return BeforeDocumentFunction(token); case CssState.InDocumentFunction: return InDocumentFunction(token); case CssState.AfterDocumentFunction: return AfterDocumentFunction(token); case CssState.BetweenDocumentFunctions: return BetweenDocumentFunctions(token); case CssState.BeforeKeyframesName: return BeforeKeyframesName(token); case CssState.BeforeKeyframesData: return BeforeKeyframesData(token); case CssState.KeyframesData: return KeyframesData(token); case CssState.InHexValue: return InHexValue(token); case CssState.InFunction: return InValueFunction(token); default: return false; } } public static Selector ParseSelector(string selector, IConfiguration configuration = null) { CssTokenizer cssTokenizer = new CssTokenizer(new SourceManager(selector, configuration ?? Configuration.Default)); IEnumerable<CssToken> tokens = cssTokenizer.Tokens; CssSelectorConstructor cssSelectorConstructor = Pool.NewSelectorConstructor(); foreach (CssToken item in tokens) { cssSelectorConstructor.Apply(item); } Selector result = cssSelectorConstructor.Result; cssSelectorConstructor.ToPool(); return result; } public static CSSStyleSheet ParseStyleSheet(string stylesheet, IConfiguration configuration = null) { CssParser cssParser = new CssParser(stylesheet, configuration ?? Configuration.Default); return cssParser.Result; } public static CSSRule ParseRule(string rule, IConfiguration configuration = null) { CssParser cssParser = new CssParser(rule, configuration ?? Configuration.Default); cssParser.skipExceptions = false; cssParser.Parse(); if (cssParser.sheet.CssRules.Length > 0) return cssParser.sheet.CssRules[0]; return null; } public static CSSStyleDeclaration ParseDeclarations(string declarations, IConfiguration configuration = null) { CSSStyleDeclaration cSSStyleDeclaration = new CSSStyleDeclaration(); AppendDeclarations(cSSStyleDeclaration, declarations, configuration); return cSSStyleDeclaration; } public static CSSProperty ParseDeclaration(string declarations, IConfiguration configuration = null) { CssParser cssParser = new CssParser(declarations, configuration ?? Configuration.Default); CSSStyleRule cSSStyleRule = new CSSStyleRule(); cssParser.AddRule(cSSStyleRule); cssParser.state = CssState.InDeclaration; cssParser.skipExceptions = false; cssParser.Parse(); if (cSSStyleRule.Style.Length == 0) return null; return cSSStyleRule.Style.Get(0); } public static CSSValue ParseValue(string source, IConfiguration configuration = null) { CssParser cssParser = new CssParser(source, configuration ?? Configuration.Default); CSSProperty cSSProperty = cssParser.property = new CSSProperty(string.Empty); cssParser.skipExceptions = false; cssParser.state = CssState.BeforeValue; cssParser.Parse(); return cSSProperty.Value; } internal static CSSValueList ParseValueList(string source, IConfiguration configuration = null) { CssParser cssParser = new CssParser(source, configuration); CSSProperty cSSProperty = cssParser.property = new CSSProperty(string.Empty); cssParser.skipExceptions = false; cssParser.state = CssState.InValueList; cssParser.Parse(); if (!cSSProperty.HasValue) return new CSSValueList(); CSSValueList cSSValueList = (cSSProperty.Value as CSSValueList) ?? new CSSValueList(cSSProperty.Value); for (int i = 0; i < cSSValueList.Length; i++) { if (cSSValueList[i] == CSSValue.Separator) { for (int num = cSSValueList.Length - 1; num >= i; num--) { cSSValueList.Remove(cSSValueList[num]); } break; } } return cSSValueList; } internal static List<CSSValueList> ParseMultipleValues(string source, IConfiguration configuration = null) { CssParser cssParser = new CssParser(source, configuration); CSSProperty cSSProperty = new CSSProperty(string.Empty); List<CSSValueList> list = new List<CSSValueList>(); cssParser.property = cSSProperty; cssParser.skipExceptions = false; cssParser.state = CssState.InValuePool; cssParser.Parse(); if (cSSProperty.HasValue) { CSSValueList cSSValueList = (cSSProperty.Value as CSSValueList) ?? new CSSValueList(cSSProperty.Value); CSSValueList cSSValueList2 = new CSSValueList(); foreach (CSSValue item in cSSValueList) { if (item == CSSValue.Separator) { if (cSSValueList2.Length > 0) list.Add(cSSValueList2); cSSValueList2 = new CSSValueList(); } else cSSValueList2.Add(item); } if (cSSValueList2.Length > 0) list.Add(cSSValueList2); cSSValueList2 = null; } return list; } internal static CSSKeyframeRule ParseKeyframeRule(string rule, IConfiguration configuration = null) { CssParser cssParser = new CssParser(rule, configuration); CSSKeyframeRule cSSKeyframeRule = new CSSKeyframeRule(); cssParser.AddRule(cSSKeyframeRule); cssParser.skipExceptions = false; cssParser.state = CssState.InKeyframeText; cssParser.Parse(); return cSSKeyframeRule; } internal static void AppendDeclarations(CSSStyleDeclaration list, string declarations, IConfiguration configuration = null) { CssParser cssParser = new CssParser(declarations, configuration ?? Configuration.Default); cssParser.skipExceptions = false; if (list.ParentRule != null) cssParser.AddRule(list.ParentRule); else cssParser.AddRule(new CSSStyleRule(list)); cssParser.state = CssState.InDeclaration; cssParser.Parse(); } private void RaiseErrorOccurred(ErrorCode code) { value.IsFaulted = true; if (this.ParseError != null) { ParseErrorEventArgs parseErrorEventArgs = new ParseErrorEventArgs((int)code, Errors.GetError(code)); parseErrorEventArgs.Line = tokenizer.Stream.Line; parseErrorEventArgs.Column = tokenizer.Stream.Column; this.ParseError(this, parseErrorEventArgs); } } } }