private static CSSRule ParseFontFace(AtRule rule, ref string OriginalCss) { CSSFontFaceRule fontrule = new CSSFontFaceRule(); int startindex = 0; int endindex = 0; int endselectindex = -1; foreach (var item in rule.prelude) { if (startindex == 0) { startindex = item.startindex; } if (item.endindex > endselectindex) { endselectindex = item.endindex; } } CSSStyleDeclaration style = ParseDeclarations(rule.block, ref endindex, ref OriginalCss); fontrule.style = style; fontrule.StartIndex = startindex; fontrule.EndIndex = endindex; fontrule.EndSelectorIndex = endselectindex - fontrule.StartIndex + 1; return(fontrule); }
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); }
private static CSSRule ParseMediaRule(AtRule rule, CSSStyleSheet parentSheet, ref string OriginalCss) { CSSMediaRule mediarule = new CSSMediaRule(); mediarule.parentStyleSheet = parentSheet; string media = string.Empty; string wholeconditiontext = string.Empty; int startindex = -1; int endindex = -1; int endindexselector = -1; startindex = rule.prelude[0].startindex; // the first componentvalue is a preservedtoken and it media. rule.prelude.RemoveAt(0); wholeconditiontext = ComponentValueExtension.getString(rule.prelude, ref startindex, ref endindexselector, ref OriginalCss); foreach (var item in wholeconditiontext.Split(',')) { mediarule.media.appendMedium(item); } CSSRuleList blockrulelist = ParseMediaRuleList(rule.block, ref endindex, mediarule, ref OriginalCss); if (blockrulelist != null) { mediarule.cssRules = blockrulelist; } mediarule.conditionText = wholeconditiontext; //SelectorText is assigned in a different way now. // mediarule.selectorText = wholeconditiontext; /// NON-W3C. mediarule.StartIndex = rule.startindex; if (rule.endindex > endindex) { endindex = rule.endindex; } mediarule.EndIndex = endindex; mediarule.EndSelectorIndex = endindexselector - mediarule.StartIndex + 1; return(mediarule); }
/// <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); }
public CssNode ReadAtRule() { // ATKEYWORD S* any* [ block | ';' S* ]; // @{keyword} ... // @import "subs.css"; // @media print { Read(TokenKind.AtSymbol, LexicalMode.Rule); // Read @ var ruleType = RuleType.Unknown; var atName = Read(); // read name ReadTrivia(); switch (atName.Text) { case "charset" : ruleType = RuleType.Charset; break; case "import" : return ReadImportRule(); case "font-face" : return ReadFontFaceRule(); case "media" : return ReadMediaRule(); case "page" : ruleType = RuleType.Page; break; case "keyframes" : return ReadKeyframesRule(); case "mixin" : return ReadMixinBody(); case "if" : return ReadIfRule(); } string selectorText = null; if (current.Kind == TokenKind.Name) { selectorText = ReadSpan().ToString(); } var rule = new AtRule(atName.Text, ruleType, selectorText ?? ""); switch (current.Kind) { case TokenKind.BlockStart: ReadBlock(rule); break; // { case TokenKind.Semicolon: tokenizer.Read(); break; // ; } return rule; }
/// <summary> /// 5.4.1. Consume a list of rules /// </summary> /// <param name="tokenizer"></param> /// <param name="top_level_flag"></param> /// <returns></returns> private List <Rule> ConsumeListOfRules(bool top_level_flag) { //To consume a list of rules: //Create an initially empty list of rules. List <Rule> rulelist = new List <Rule>(); cssToken token; while (true) { //Repeatedly consume the next input token: token = ConsumeNextToken(); //<whitespace-token> if (token.Type == enumTokenType.whitespace) { //Do nothing. } //<EOF-token> else if (token.Type == enumTokenType.EOF) { //Return the list of rules. return(rulelist); } //<CDO-token> //<CDC-token> else if (token.Type == enumTokenType.CDC || token.Type == enumTokenType.CDO) { //If the top-level flag is set, do nothing. if (!top_level_flag) { //Otherwise, reconsume the current input token. Consume a qualified rule. If anything is returned, append it to the list of rules. ReconsumeToken(); QualifiedRule rule = ConsumeQualifiedRule(); if (rule != null) { rulelist.Add(rule); } } } //<at-keyword-token> else if (token.Type == enumTokenType.at_keyword) { //Reconsume the current input token. Consume an at-rule. If anything is returned, append it to the list of rules. ReconsumeToken(); AtRule rule = ConsumeAtRule(); if (rule != null) { rulelist.Add(rule); } } //anything else else { //Reconsume the current input token. Consume a qualified rule. If anything is returned, append it to the list of rules. ReconsumeToken(); QualifiedRule rule = ConsumeQualifiedRule(); if (rule != null) { rulelist.Add(rule); } } } }
/// <summary> /// 5.4.2. Consume an at-rule /// </summary> /// <returns></returns> private AtRule ConsumeAtRule() { //To consume an at-rule: //Create a new at-rule with its name set to the value of the current input token, its prelude initially set to an empty list, and its value initially set to nothing. AtRule rule = new AtRule(); int startindex = -1; cssToken token = null; while (true) { //Repeatedly consume the next input token: token = ConsumeNextToken(); if (startindex == -1) { startindex = token.startIndex; } //<semicolon-token> //<EOF-token> if (token.Type == enumTokenType.semicolon || token.Type == enumTokenType.EOF) { //Return the at-rule. rule.startindex = startindex; rule.endindex = token.endIndex; if (token.Type == enumTokenType.EOF) { rule.endindex = rule.endindex - 1; } return(rule); } //<{-token> else if (token.Type == enumTokenType.curly_bracket_left) { //Consume a simple block and assign it to the at-rule’s block. Return the at-rule. SimpleBlock simpleblock = ConsumeSimpleBlock(); simpleblock.startindex = token.startIndex; rule.block = simpleblock; rule.startindex = startindex; rule.endindex = simpleblock.endindex; return(rule); } //simple block with an associated token of <{-token> //Assign the block to the at-rule’s block. Return the at-rule. ///TODO: ???? check what does this means??? //anything else else { //Reconsume the current input token. Consume a component value. Append the returned value to the at-rule’s prelude. ReconsumeToken(); ComponentValue value = ConsumeComponentValue(); rule.prelude.Add(value); } } }