/// <summary> /// Parse a complex font property value that contains multiple css properties into specific css properties. /// </summary> /// <param name="propValue">the value of the property to parse to specific values</param> /// <param name="properties">the properties collection to add the specific properties to</param> private void ParseFontProperty(string propValue, Dictionary <string, string> properties) { int mustBePos; string mustBe = RegexParserUtils.Search(RegexParserUtils.CssFontSizeAndLineHeight, propValue, out mustBePos); if (!string.IsNullOrEmpty(mustBe)) { mustBe = mustBe.Trim(); //Check for style||variant||weight on the left string leftSide = propValue.Substring(0, mustBePos); string fontStyle = RegexParserUtils.Search(RegexParserUtils.CssFontStyle, leftSide); string fontVariant = RegexParserUtils.Search(RegexParserUtils.CssFontVariant, leftSide); string fontWeight = RegexParserUtils.Search(RegexParserUtils.CssFontWeight, leftSide); //Check for family on the right string rightSide = propValue.Substring(mustBePos + mustBe.Length); string fontFamily = rightSide.Trim(); //Parser.Search(Parser.CssFontFamily, rightSide); //TODO: Would this be right? //Check for font-size and line-height string fontSize = mustBe; string lineHeight = string.Empty; if (mustBe.Contains("/") && mustBe.Length > mustBe.IndexOf("/", StringComparison.Ordinal) + 1) { int slashPos = mustBe.IndexOf("/", StringComparison.Ordinal); fontSize = mustBe.Substring(0, slashPos); lineHeight = mustBe.Substring(slashPos + 1); } if (!string.IsNullOrEmpty(fontFamily)) { properties["font-family"] = ParseFontFamilyProperty(fontFamily); } if (!string.IsNullOrEmpty(fontStyle)) { properties["font-style"] = fontStyle; } if (!string.IsNullOrEmpty(fontVariant)) { properties["font-variant"] = fontVariant; } if (!string.IsNullOrEmpty(fontWeight)) { properties["font-weight"] = fontWeight; } if (!string.IsNullOrEmpty(fontSize)) { properties["font-size"] = fontSize; } if (!string.IsNullOrEmpty(lineHeight)) { properties["line-height"] = lineHeight; } } else { // Check for: caption | icon | menu | message-box | small-caption | status-bar //TODO: Interpret font values of: caption | icon | menu | message-box | small-caption | status-bar } }
/// <summary> /// Parse given stylesheet for media CSS blocks<br/> /// This blocks are added under the specific media block they are found. /// </summary> /// <param name="cssData">the CSS data to fill with parsed CSS objects</param> /// <param name="atrule">the @media rule to parse</param> private void ParseMediaAtRule(CssData cssData, string atrule) { //Extract specified media types MatchCollection types = RegexParserUtils.Match(RegexParserUtils.CssMediaTypes, atrule); if (types.Count == 1) { string line = types[0].Value; //Get blocks inside the at-rule var insideBlocks = RegexParserUtils.Match(RegexParserUtils.CssBlocks, atrule); //Get specified media types in the at-rule string[] mediaTypes = line.Substring(6, line.Length - 7).Split(_cssWhitespace, StringSplitOptions.RemoveEmptyEntries); //Scan media types foreach (string mediaType in mediaTypes) { //Scan blocks and feed them to the style sheet foreach (Match insideBlock in insideBlocks) { FeedStyleBlock(cssData, insideBlock.Value, mediaType); } } } }
/// <summary> /// Parse imports and return urls to imported stylesheets /// </summary> /// <param name="stylesheet">The stylesheet to parse</param> /// <returns>CSS imports</returns> private List <string> ParseImportStatement(string stylesheet) { int startIdx = 0; List <string> imports = new List <string>(1); MatchCollection importsCollection = RegexParserUtils.Match(RegexParserUtils.CssImportRule, stylesheet); foreach (Match import in importsCollection) { string importValue = import.Value; int urlStartIdx = importValue.IndexOf("url(", StringComparison.InvariantCultureIgnoreCase); if (urlStartIdx >= 0) { urlStartIdx += 4; int urlEndIdx = importValue.IndexOf(')', urlStartIdx); if (urlEndIdx > -1) { urlEndIdx -= 1; while (urlStartIdx < urlEndIdx && (char.IsWhiteSpace(importValue[urlStartIdx]) || importValue[urlStartIdx] == '\'' || importValue[urlStartIdx] == '"')) { urlStartIdx++; } while (urlStartIdx < urlEndIdx && (char.IsWhiteSpace(importValue[urlEndIdx]) || importValue[urlEndIdx] == '\'' || importValue[urlEndIdx] == '"')) { urlEndIdx--; } if (urlStartIdx <= urlEndIdx) { string url = importValue.Substring(urlStartIdx, urlEndIdx - urlStartIdx + 1); imports.Add(url); } } } else { urlStartIdx = importValue.IndexOf('"'); urlStartIdx = urlStartIdx == -1 ? importValue.IndexOf('\'') : urlStartIdx; if (urlStartIdx >= 0) { int urlEndIdx = importValue.LastIndexOf('"'); urlEndIdx = urlEndIdx == -1 ? importValue.IndexOf('\'') : urlEndIdx; string url = importValue.Substring(urlStartIdx + 1, urlEndIdx - urlStartIdx - 1); imports.Add(url); } } } return(imports); }
private void ParsePageAtRule(CssData cssData, string atrule) { //Get blocks inside the at-rule var insideBlocks = RegexParserUtils.Match(RegexParserUtils.CssBlocks, atrule); // TODO: add page rules int startIdx = 0; string nestedAtrule; while ((nestedAtrule = RegexParserUtils.GetCssAtRules(atrule, ref startIdx)) != null) { // TODO: add margin box rules } }
/// <summary> /// Parse given stylesheet for media CSS blocks<br/> /// This blocks are added under the specific media block they are found. /// </summary> /// <param name="cssData">the CSS data to fill with parsed CSS objects</param> /// <param name="stylesheet">the stylesheet to parse</param> private void ParseAtRuleBlocks(CssData cssData, string stylesheet) { int startIdx = 0; string atrule; while ((atrule = RegexParserUtils.GetCssAtRules(stylesheet, ref startIdx)) != null) { //Just process @media rules if (atrule.StartsWith("@media", StringComparison.InvariantCultureIgnoreCase)) { ParseMediaAtRule(cssData, atrule); } else if (atrule.StartsWith("@page", StringComparison.InvariantCultureIgnoreCase)) { ParsePageAtRule(cssData, atrule); } } }
/// <summary> /// Parse given stylesheet for media CSS blocks<br/> /// This blocks are added under the specific media block they are found. /// </summary> /// <param name="cssData">the CSS data to fill with parsed CSS objects</param> /// <param name="stylesheet">the stylesheet to parse</param> private void ParseMediaStyleBlocks(CssData cssData, string stylesheet) { int startIdx = 0; string atrule; while ((atrule = RegexParserUtils.GetCssAtRules(stylesheet, ref startIdx)) != null) { //Just process @media rules if (!atrule.StartsWith("@media", StringComparison.InvariantCultureIgnoreCase)) { continue; } //Extract specified media types MatchCollection types = RegexParserUtils.Match(RegexParserUtils.CssMediaTypes, atrule); if (types.Count == 1) { string line = types[0].Value; if (line.StartsWith("@media", StringComparison.InvariantCultureIgnoreCase) && line.EndsWith("{")) { //Get specified media types in the at-rule string[] media = line.Substring(6, line.Length - 7).Split(' '); //Scan media types foreach (string t in media) { if (!String.IsNullOrEmpty(t.Trim())) { //Get blocks inside the at-rule var insideBlocks = RegexParserUtils.Match(RegexParserUtils.CssBlocks, atrule); //Scan blocks and feed them to the style sheet foreach (Match insideBlock in insideBlocks) { FeedStyleBlock(cssData, insideBlock.Value, t.Trim()); } } } } } } }