Пример #1
0
        private static CSSRule ParseAtRule(AtRule rule, CSSStyleSheet parentSheet, string baseurl, bool downloadImportRule, ref string OriginalCss)
        {
            /// the first item in rule is the atkeyword.

            if (rule.prelude[0].Type == CompoenentValueType.preservedToken)
            {
                PreservedToken token = rule.prelude[0] as PreservedToken;
                if (token.token.Type == enumTokenType.at_keyword)
                {
                    at_keyword_token keywordToken = token.token as at_keyword_token;

                    if (keywordToken.value.ToLower() == "import")
                    {
                        return(ParseImportRule(rule, baseurl, downloadImportRule, ref OriginalCss));
                    }
                    else if (keywordToken.value.ToLower() == "media")
                    {
                        return(ParseMediaRule(rule, parentSheet, ref OriginalCss));
                    }
                    else if (keywordToken.value.ToLower() == "font-face")
                    {
                        return(ParseFontFace(rule, ref OriginalCss));
                    }
                }
            }

            return(null);
        }
Пример #2
0
        /// <summary>
        /// 5.4.6. Consume a component value
        /// </summary>
        /// <returns></returns>
        private ComponentValue ConsumeComponentValue()
        {
            //Consume the next input token.
            cssToken token = ConsumeNextToken();

            //If the current input token is a <{-token>, <[-token>, or <(-token>, consume a simple block and return it.
            if (token.Type == enumTokenType.curly_bracket_left || token.Type == enumTokenType.square_bracket_left || token.Type == enumTokenType.round_bracket_left)
            {
                SimpleBlock simpleblock = ConsumeSimpleBlock();
                simpleblock.startindex = token.startIndex;

                return(simpleblock);
            }
            //Otherwise, if the current input token is a <function-token>, consume a function and return it.
            else if (token.Type == enumTokenType.function)
            {
                Function func = ConsumeFunction();
                func.startindex = token.startIndex;
                return(func);
            }
            else
            {
                //Otherwise, return the current input token.
                PreservedToken preservedtoken = new PreservedToken();
                preservedtoken.token      = token;
                preservedtoken.startindex = token.startIndex;
                preservedtoken.endindex   = token.endIndex;
                return(preservedtoken);
            }
        }
Пример #3
0
        /// <summary>
        /// Consume a list of declaration from a simple block.
        /// </summary>
        /// <param name="block"></param>
        /// <returns></returns>
        private static CSSStyleDeclaration ParseDeclarations(SimpleBlock block, ref int endindex, ref string CssText)
        {
            CSSStyleDeclaration declarations = new CSSStyleDeclaration();
            string csstext = string.Empty;

            CSSDeclaration onedeclaration = null;
            bool           colonfound     = false; // check value before or after colon.

            int valuecount = block.value.Count;

            for (int i = 0; i < valuecount; i++)
            {
                ComponentValue item = block.value[i];

                if (item.endindex > endindex)
                {
                    endindex = item.endindex;
                }

                if (item.Type == CompoenentValueType.preservedToken)
                {
                    PreservedToken token = item as PreservedToken;

                    if (token.token.Type == enumTokenType.ident)
                    {
                        // the first ident is the start of one declaration.
                        if (onedeclaration == null)
                        {
                            onedeclaration = new CSSDeclaration();
                            ident_token identtoken = token.token as ident_token;
                            onedeclaration.propertyname = identtoken.value;
                            colonfound = false;
                        }
                        else
                        {
                            onedeclaration.value += token.token.GetString(ref CssText);
                        }
                    }
                    else if (token.token.Type == enumTokenType.semicolon || token.token.Type == enumTokenType.EOF)
                    {
                        // this is the end of one declaration.
                        declarations.item.Add(onedeclaration);
                        onedeclaration = null;
                        colonfound     = false;
                    }

                    else if (colonfound == false)
                    {
                        if (token.token.Type == enumTokenType.colon)
                        {
                            colonfound = true;
                        }
                        else if (token.token.Type == enumTokenType.whitespace)
                        {
                            // white space do nothing.
                        }
                        else
                        {
                            // the next one must be white space or colon, otherwise, error.
                            //TODO: onError.
                        }
                    }

                    else if (token.token.Type == enumTokenType.delim && ((delim_token)token.token).value == '!')
                    {
                        if ((i + 1) < valuecount)
                        {
                            if (block.value[i + 1].Type == CompoenentValueType.preservedToken)
                            {
                                PreservedToken important = block.value[i + 1] as PreservedToken;
                                if (important.token.Type == enumTokenType.ident)
                                {
                                    ident_token importantident = important.token as ident_token;
                                    if (importantident.value.ToLower() == "important" && onedeclaration != null)
                                    {
                                        onedeclaration.important = true;
                                    }
                                }
                            }

                            // has to consume the important now, because value has been processed.
                            i = i + 1;
                        }
                    }
                    else
                    {
                        /// append the value to declaration value.
                        if (onedeclaration != null)
                        {
                            onedeclaration.value += token.token.GetString(ref CssText);
                        }
                    }
                }
                else if (item.Type == CompoenentValueType.function)
                {
                    Function func = item as Function;

                    if (onedeclaration == null)
                    {
                        onedeclaration = new CSSDeclaration();
                        onedeclaration.propertyname = func.getString(ref CssText);
                        colonfound = false;
                    }
                    else
                    {
                        if (colonfound)
                        {
                            onedeclaration.value += func.getString(ref CssText);
                        }
                        else
                        {
                            onedeclaration.propertyname += func.getString(ref CssText);
                        }
                    }
                }
            }



            if (onedeclaration != null && !string.IsNullOrEmpty(onedeclaration.propertyname))
            {
                declarations.item.Add(onedeclaration);
                onedeclaration = null;
                colonfound     = false;
            }


            if (block.endindex > endindex)
            {
                endindex = block.endindex;
            }

            return(declarations);
        }
Пример #4
0
        /// <summary>
        /// consume a list of cssrule from simpleblock,
        /// Recursive.
        /// </summary>
        /// <param name="block"></param>
        /// <returns></returns>
        private static CSSRuleList ParseMediaRuleList(SimpleBlock block, ref int endindex, CSSMediaRule parentmediarule, ref string OriginalCss)
        {
            int         count    = block.value.Count;
            CSSRuleList rulelist = new CSSRuleList();

            MediaRuleParseState state = MediaRuleParseState.init;

            CSSStyleRule stylerule = null;
            CSSMediaRule mediarule = null;

            string media = string.Empty;
            string wholeconditiontext = string.Empty;

            int startindex = -1;

            for (int i = 0; i < count; i++)
            {
                if (block.value[i].endindex > endindex)
                {
                    endindex = block.value[i].endindex;
                }

                if (startindex < 0)
                {
                    startindex = block.value[i].startindex;
                }

                switch (state)
                {
                case MediaRuleParseState.init:
                {
                    if (block.value[i].Type == CompoenentValueType.preservedToken)
                    {
                        PreservedToken pretoken = block.value[i] as PreservedToken;

                        if (pretoken.token.Type == enumTokenType.whitespace)
                        {
                            // ignored whitespace at the beginning.
                        }
                        else if (pretoken.token.Type == enumTokenType.at_keyword)
                        {
                            // at keyword token, only handle media now.
                            // others to be added.
                            at_keyword_token token = pretoken.token as at_keyword_token;
                            if (token.value.ToLower() == "media")
                            {
                                state = MediaRuleParseState.mediarule;
                                i     = i - 1;     // reconsume to have correct startindex.
                            }
                            else
                            {
                                // other at rules.
                                state = MediaRuleParseState.OtherAtRule;
                                i     = i - 1;
                            }
                        }

                        /// else treat as regular style rule.
                        else
                        {
                            state = MediaRuleParseState.stylerule;
                            i     = i - 1;     // reconsume.
                        }
                    }
                    break;
                }

                case MediaRuleParseState.stylerule:
                {
                    if (stylerule == null)
                    {
                        stylerule  = new CSSStyleRule();
                        startindex = block.value[i].startindex;
                    }

                    if (block.value[i].Type == CompoenentValueType.preservedToken)
                    {
                        PreservedToken pretoken = block.value[i] as PreservedToken;
                        // not a defined way to parse the selector, assembly them back and give it to selector module.
                        // in the new way of getting selectorText, we have not need to assign it any more.
                        //stylerule.selectorText += pretoken.token.getString();
                    }
                    else if (block.value[i].Type == CompoenentValueType.simpleBlock)
                    {
                        int endselectorindex = block.value[i].startindex;

                        stylerule.style = ParseDeclarations(block.value[i] as SimpleBlock, ref endindex, ref OriginalCss);

                        stylerule.StartIndex = startindex;
                        stylerule.EndIndex   = endindex;

                        stylerule.EndSelectorIndex = endselectorindex - stylerule.StartIndex;

                        stylerule.parentRule = parentmediarule;

                        stylerule.parentStyleSheet = parentmediarule.parentStyleSheet;

                        rulelist.appendRule(stylerule);
                        stylerule = null;

                        state      = MediaRuleParseState.init;
                        startindex = -1;
                    }


                    break;
                }

                case MediaRuleParseState.mediarule:
                {
                    if (mediarule == null)
                    {
                        mediarule          = new CSSMediaRule();
                        media              = string.Empty;
                        wholeconditiontext = string.Empty;
                        startindex         = block.value[i].startindex;

                        mediarule.parentStyleSheet = parentmediarule.parentStyleSheet;
                        mediarule.parentRule       = parentmediarule;
                    }

                    if (block.value[i].Type == CompoenentValueType.preservedToken)
                    {
                        PreservedToken pretoken = block.value[i] as PreservedToken;

                        if (pretoken.token.Type == enumTokenType.comma)
                        {
                            if (!string.IsNullOrEmpty(media))
                            {
                                mediarule.media.appendMedium(media.Trim());
                                media = string.Empty;
                            }
                            wholeconditiontext += ",";
                        }
                        else
                        {
                            // can be delim token.
                            if (string.IsNullOrEmpty(media) && pretoken.token.Type == enumTokenType.whitespace)
                            {
                                // the start of whitespace will be ignored.
                            }
                            else
                            {
                                media += pretoken.token.GetString(ref OriginalCss);
                                wholeconditiontext += pretoken.token.GetString(ref OriginalCss);
                            }
                        }
                    }
                    else if (block.value[i].Type == CompoenentValueType.simpleBlock)
                    {
                        CSSRuleList mediarulelist = ParseMediaRuleList(block.value[i] as SimpleBlock, ref endindex, mediarule, ref OriginalCss);

                        mediarule.cssRules = mediarulelist;

                        if (!string.IsNullOrEmpty(media))
                        {
                            mediarule.media.appendMedium(media.Trim());
                            wholeconditiontext += media;
                        }

                        mediarule.conditionText = wholeconditiontext;
                        mediarule.selectorText  = wholeconditiontext;        /// NON-W3C.

                        mediarule.StartIndex = startindex;
                        mediarule.EndIndex   = endindex;

                        rulelist.appendRule(mediarule);

                        state              = 0;
                        mediarule          = null;
                        media              = string.Empty;
                        wholeconditiontext = string.Empty;
                        startindex         = -1;
                    }

                    break;
                }

                case MediaRuleParseState.OtherAtRule:
                {
                    //if (mediarule == null)
                    //{
                    //    mediarule = new CSSMediaRule();
                    //    media = string.Empty;
                    //    wholeconditiontext = string.Empty;
                    //    startindex = block.value[i].startindex;

                    //    mediarule.parentStyleSheet = parentmediarule.parentStyleSheet;
                    //    mediarule.parentRule = parentmediarule;
                    //}

                    if (block.value[i].Type == CompoenentValueType.preservedToken)
                    {
                        //PreservedToken pretoken = block.value[i] as PreservedToken;

                        //if (pretoken.token.Type == enumTokenType.comma)
                        //{
                        //    if (!string.IsNullOrEmpty(media))
                        //    {
                        //        mediarule.media.appendMedium(media.Trim());
                        //        media = string.Empty;
                        //    }
                        //    wholeconditiontext += ",";
                        //}
                        //else
                        //{
                        //    // can be delim token.
                        //    if (string.IsNullOrEmpty(media) && pretoken.token.Type == enumTokenType.whitespace)
                        //    {
                        //        // the start of whitespace will be ignored.
                        //    }
                        //    else
                        //    {
                        //        media += pretoken.token.GetString(ref OriginalCss);
                        //        wholeconditiontext += pretoken.token.GetString(ref OriginalCss);
                        //    }
                        //}
                    }
                    else if (block.value[i].Type == CompoenentValueType.simpleBlock)
                    {
                        // not implemented now.
                        //CSSRuleList mediarulelist = ParseMediaRuleList(block.value[i] as SimpleBlock, ref endindex, mediarule, ref OriginalCss);

                        //mediarule.cssRules = mediarulelist;

                        //if (!string.IsNullOrEmpty(media))
                        //{
                        //    mediarule.media.appendMedium(media.Trim());
                        //    wholeconditiontext += media;
                        //}

                        //mediarule.conditionText = wholeconditiontext;
                        //mediarule.selectorText = wholeconditiontext; /// NON-W3C.

                        //mediarule.StartIndex = startindex;
                        //mediarule.EndIndex = endindex;

                        //rulelist.appendRule(mediarule);

                        state      = MediaRuleParseState.init;
                        startindex = -1;
                    }

                    break;
                }

                default:
                    break;
                }
            }


            if (stylerule != null)
            {
                if (stylerule.EndIndex > stylerule.StartIndex)
                {
                    rulelist.appendRule(stylerule);
                }
                stylerule = null;
            }

            if (mediarule != null)
            {
                rulelist.appendRule(mediarule);
                mediarule = null;
            }
            return(rulelist);
        }
Пример #5
0
        /// <summary>
        /// The @import at-rule is a simple statement. After its name, it takes a single string or url() function to indicate the stylesheet that it should import.
        /// </summary>
        /// <param name="rule"></param>
        /// <returns></returns>
        private static CSSRule ParseImportRule(AtRule rule, string baseurl, bool downloadImportRule, ref string OriginalCss)
        {
            /// the import starts with import atkeyword token.
            /// it should have been checked before calling this method, can be ignored.
            PreservedToken token = rule.prelude[0] as PreservedToken;

            int count = rule.prelude.Count;

            CSSImportRule importrule = new CSSImportRule();
            string        media      = string.Empty;

            int startindex = -1;
            int endindex   = -1;

            for (int i = 0; i < count; i++)
            {
                if (startindex < 0)
                {
                    startindex = rule.prelude[i].startindex;
                }

                if (rule.prelude[i].endindex > endindex)
                {
                    endindex = rule.prelude[i].endindex;
                }

                if (rule.prelude[i].Type == CompoenentValueType.preservedToken)
                {
                    PreservedToken preservedToken = rule.prelude[i] as PreservedToken;

                    /// ignore the whitespace and at-keyword token.
                    if (preservedToken.token.Type == enumTokenType.at_keyword || (string.IsNullOrEmpty(importrule.href) && preservedToken.token.Type == enumTokenType.whitespace))
                    {
                        continue;
                    }

                    if (string.IsNullOrEmpty(importrule.href))
                    {
                        if (preservedToken.token.Type == enumTokenType.String)
                        {
                            string_token stringtoken = preservedToken.token as string_token;
                            string       url         = string.Empty;

                            if (string.IsNullOrEmpty(baseurl))
                            {
                                url = stringtoken.value;
                            }
                            else
                            {
                                url = PathHelper.combine(baseurl, stringtoken.value);
                            }

                            importrule.href = url;
                            if (downloadImportRule && !string.IsNullOrEmpty(url))
                            {
                                importrule.stylesheet = CSSParser.ParseCSSStyleSheetFromUrl(url);
                            }
                        }
                        else if (preservedToken.token.Type == enumTokenType.url)
                        {
                            url_token urltoken = preservedToken.token as url_token;

                            string url = string.Empty;
                            if (string.IsNullOrEmpty(baseurl))
                            {
                                url = urltoken.value;
                            }
                            else
                            {
                                url = PathHelper.combine(baseurl, urltoken.value);
                            }

                            importrule.href = url;
                            if (downloadImportRule && !string.IsNullOrEmpty(url))
                            {
                                importrule.stylesheet = CSSParser.ParseCSSStyleSheetFromUrl(url);
                            }
                        }
                        else
                        {
                            // must start with a string or url token as the next.
                            string error = "this is an error";
                        }
                    }
                    else
                    {
                        // the import rule has href already, next is the media rules.
                        if (preservedToken.token.Type == enumTokenType.comma || preservedToken.token.Type == enumTokenType.semicolon)
                        {
                            if (!string.IsNullOrEmpty(media))
                            {
                                importrule.media.appendMedium(media.Trim());
                                media = string.Empty;
                            }
                        }
                        else
                        {
                            // can be delim token.
                            if (string.IsNullOrEmpty(media) && preservedToken.token.Type == enumTokenType.whitespace)
                            {
                                // the start of whitespace will be ignored.
                            }
                            else
                            {
                                media += preservedToken.token.GetString(ref OriginalCss);
                            }
                        }
                    }
                }

                else if (rule.prelude[i].Type == CompoenentValueType.function)
                {
                    Function urlfunction = rule.prelude[i] as Function;
                    string   href        = string.Empty;
                    if (urlfunction.name == "url")
                    {
                        foreach (var item in urlfunction.value)
                        {
                            if (item.Type == CompoenentValueType.preservedToken)
                            {
                                PreservedToken pretoken = item as PreservedToken;
                                if (pretoken.token.Type == enumTokenType.String)
                                {
                                    string_token stringtoken = pretoken.token as string_token;
                                    href += stringtoken.value;
                                }
                            }
                        }
                    }

                    if (!string.IsNullOrEmpty(href))
                    {
                        importrule.href = href;
                    }
                }

                else if (rule.prelude[i].Type == CompoenentValueType.simpleBlock)
                {
                    // simple block is the block like  screen and (min-width:300);
                    SimpleBlock block = rule.prelude[i] as SimpleBlock;

                    string mediarule = string.Empty;
                    foreach (var item in block.value)
                    {
                        if (item.Type == CompoenentValueType.preservedToken)
                        {
                            PreservedToken pretoken = item as PreservedToken;
                            mediarule += pretoken.token.GetString(ref OriginalCss);

                            if (token.token.endIndex > endindex)
                            {
                                endindex = token.token.endIndex;
                            }
                        }
                    }

                    if (block.token.Type == enumTokenType.round_bracket_left || block.token.Type == enumTokenType.round_bracket_right)
                    {
                        mediarule = "(" + mediarule + ")";
                    }
                    else if (block.token.Type == enumTokenType.square_bracket_left || block.token.Type == enumTokenType.square_bracket_right)
                    {
                        mediarule = "[" + mediarule + "]";
                    }
                    else if (block.token.Type == enumTokenType.curly_bracket_left || block.token.Type == enumTokenType.curly_bracket_right)
                    {
                        mediarule = "{" + mediarule + "}";
                    }

                    media += mediarule;
                }
            }

            if (!string.IsNullOrEmpty(media))
            {
                importrule.media.appendMedium(media.Trim());
                media = string.Empty;
            }

            importrule.StartIndex = startindex;
            if (rule.endindex > endindex)
            {
                endindex = rule.endindex;
            }
            importrule.EndIndex = endindex;

            int endselectorindex = rule.prelude[0].endindex + 1;

            ///import rule does not have one extra char like {
            // importrule.EndSelectorIndex = endselectorindex - importrule.StartIndex + 1;
            importrule.EndSelectorIndex = endselectorindex - importrule.StartIndex;

            return(importrule);
        }