private static CssPseudoClass[] ParsePseudoClasses(CssStringStreamReader reader)
        {
            var classes = new List <CssPseudoClass>();

            while (reader.CurrentChar == ':')
            {
                reader.Advance();
                if (!reader.TryReadIdentifier(out var className))
                {
                    return(null);
                }
                if (CssFunctionalPseudoClass.TryConvertToFunctionalPseudoClassType(className, out var functionalClassType))
                {
                    if (!reader.Read('(') ||
                        !TryParseSelectorList(reader, out var functionalSelectors) ||
                        !reader.Read(')'))
                    {
                        return(null);
                    }
                    classes.Add(new CssFunctionalPseudoClass(functionalSelectors, functionalClassType));
                    continue;
                }
                if (CssUserActionPseudoClass.TryConvertToUserActionPseudoClassType(className, out var userActionClassType))
                {
                    classes.Add(new CssUserActionPseudoClass(userActionClassType));
                    continue;
                }

                if (CssStructuralPseudoClass.TryConvertToStructuralPseudoClassType(className, out var structuralPseudoClassType))
                {
                    if (!reader.Read('(') ||
                        !TryParseSelectorList(reader, out var structuralSelectors) ||
                        !reader.Read(')'))
                    {
                        structuralSelectors = new CssSelectorList();
                    }

                    classes.Add(new CssStructuralPseudoClass(structuralSelectors, structuralPseudoClassType));
                    continue;
                }
                return(null);    // unknown / unhandled pseudo class
            }
            return(classes.ToArray());
        }
        /// <summary>
        /// Tries to parse a collection of properties (name value pairs, e.g. 'fill:#000') of a style body
        /// </summary>
        public static bool TryParseStyleRuleBodyProperties(CssStringStreamReader reader, out Dictionary <string, CssStylePropertyValue> properties)
        {
            properties = new Dictionary <string, CssStylePropertyValue>();

            reader.SkipWhitespaceAndComments();

            var builder = new StringBuilder();

            while (!reader.IsEndOfStream && reader.CurrentChar != '}')
            {
                if (!reader.TryReadIdentifier(out var name))
                {
                    return(false);
                }

                reader.SkipWhitespaceAndComments();
                if (!reader.Read(':'))
                {
                    return(false);
                }
                reader.SkipWhitespaceAndComments();

                while (reader.CurrentChar != ';' && reader.CurrentChar != '}' && !reader.IsEndOfStream)
                {
                    builder.Append(reader.CurrentChar);
                    reader.Advance();
                }

                properties[name] = new CssStylePropertyValue(builder.ToString());
                builder.Clear();

                if (reader.CurrentChar == ';')
                {
                    reader.Read(';');
                }

                reader.SkipWhitespaceAndComments();
            }

            return(true);
        }
        public static bool TryParseRules(CssStringStreamReader reader, out CssStyleRulesList rules)
        {
            rules = new CssStyleRulesList();
            reader.SkipWhitespaceAndComments();
            while (!reader.IsEndOfStream)
            {
                if (!TryParseSelectorList(reader, out var selectors) ||
                    !reader.SkipWhitespaceAndComments() ||
                    !reader.Read('{') ||
                    !TryParseStyleRuleBodyProperties(reader, out var properties) ||
                    !reader.SkipWhitespaceAndComments() ||
                    !reader.Read('}'))
                {
                    return(false);
                }

                rules.Add(new CssStyleRule(selectors, properties));
                reader.SkipWhitespaceAndComments();
            }
            return(true);
        }