/// <summary> /// Skip over a complete block of unknown content /// </summary> public override bool Parse(ItemFactory itemFactory, ITextProvider text, TokenStream tokens) { // Save the opening token for this block OpenBlock = Children.AddCurrentAndAdvance(tokens, null); CssTokenType matchingEndType = GetMatchingTokenType(OpenBlock.TokenType); Debug.Assert(matchingEndType != CssTokenType.Unknown); // Search for the matching end of the block bool invalidBlock = false; while (!invalidBlock && tokens.CurrentToken.TokenType != matchingEndType && !tokens.CurrentToken.IsScopeBlocker()) { // Treat the contents of the block as property values so that units, functions, etc. get parsed ParseItem pi = PropertyValueHelpers.ParsePropertyValue(this, itemFactory, text, tokens); if (pi != null) { Children.Add(pi); } else { switch (tokens.CurrentToken.TokenType) { case CssTokenType.CloseCurlyBrace: case CssTokenType.CloseFunctionBrace: case CssTokenType.CloseSquareBracket: // Found a non-matching end brace/bracket, so stop parsing invalidBlock = true; break; default: Children.AddUnknownAndAdvance(itemFactory, text, tokens); break; } } } if (tokens.CurrentToken.TokenType == matchingEndType) { CloseBlock = Children.AddCurrentAndAdvance(tokens, null); } else { OpenBlock.AddParseError(ParseErrorType.CloseBraceMismatch, ParseErrorLocation.AfterItem); } return(Children.Count > 0); }
protected virtual void ParsePropertyValue(ItemFactory itemFactory, ITextProvider text, TokenStream tokens) { ParseItem item = PropertyValueHelpers.ParsePropertyValue(this, itemFactory, text, tokens); if (item != null) { Values.Add(item); Children.Add(item); } else { Children.AddUnknownAndAdvance(itemFactory, text, tokens, ParseErrorType.PropertyValueExpected); } }
protected virtual void ParseArgument(ItemFactory itemFactory, ITextProvider text, TokenStream tokens) { while (!tokens.CurrentToken.IsFunctionArgumentTerminator()) { ParseItem pi = PropertyValueHelpers.ParsePropertyValue(this, itemFactory, text, tokens); if (pi != null) { ArgumentItems.Add(pi); Children.Add(pi); } else { // An unknown item is not an error pi = Children.AddUnknownAndAdvance(itemFactory, text, tokens); ArgumentItems.Add(pi); } } }
/// <summary> /// This helps the ColorParser class to figure out the values of each color argument. /// If the output argumentValue is float.NaN then the argument can still be valid, but /// its actualy value cannot be determined. /// </summary> internal virtual bool GetColorArgumentValue(int argumentIndex, bool looseParsing, out float argumentValue) { argumentValue = 0; FunctionArgument colorArgument = (argumentIndex >= 0 && argumentIndex < Arguments.Count) ? Arguments[argumentIndex] as FunctionArgument : null; // Make sure the argument has the right number of children if (colorArgument == null || colorArgument.ArgumentItems.Count == 0 || (!looseParsing && colorArgument.ArgumentItems.Count != 1)) { return(false); } ParseItem colorNumber = colorArgument.ArgumentItems[0]; UnitType unitType = PropertyValueHelpers.GetUnitType(colorNumber); if (argumentIndex > 3) { // No color function has more than four arguments return(false); } else if (argumentIndex == 3) { // It's the alpha value if (ColorFunction == ColorFunctionType.Rgba || ColorFunction == ColorFunctionType.Hsla) { if (PropertyValueHelpers.IsValidNumber(colorNumber)) { if (float.TryParse(colorNumber.Text, NumberStyles.Number, NumberFormatInfo.InvariantInfo, out argumentValue)) { return(true); } } } } else if (ColorFunction == ColorFunctionType.Rgb || ColorFunction == ColorFunctionType.Rgba) { // Red, Green, and Blue are always a <percentage> or <integer> if (unitType == UnitType.Percentage) { if (float.TryParse(colorNumber.Text.TrimEnd('%'), NumberStyles.Number, NumberFormatInfo.InvariantInfo, out argumentValue)) { argumentValue /= 100.0f; return(true); } } else if (PropertyValueHelpers.IsValidInteger(colorNumber)) { if (int.TryParse(colorNumber.Text, out int intValue)) { argumentValue = intValue / 255.0f; return(true); } } } else if (argumentIndex == 0) { // Hue is always a <number> if (PropertyValueHelpers.IsValidNumber(colorNumber)) { if (float.TryParse(colorNumber.Text, NumberStyles.Number, NumberFormatInfo.InvariantInfo, out argumentValue)) { argumentValue /= 360.0f; return(true); } } } else { // Saturation and Lightness are always a percentage if (unitType == UnitType.Percentage) { if (float.TryParse(colorNumber.Text.TrimEnd('%'), NumberStyles.Number, NumberFormatInfo.InvariantInfo, out argumentValue)) { argumentValue /= 100.0f; return(true); } } } return(false); }