Skip to content

Commit

Permalink
Implemented conic-gradient AngleSharp#101
Browse files Browse the repository at this point in the history
  • Loading branch information
FlorianRappl committed Jun 2, 2022
1 parent 0751cbe commit 46b9c9a
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Released on Tuesday, May 31 2022.
- Updated to use AngleSharp 0.17
- Fixed casing issue with color, timing, and gradient functions (#109)
- Fixed shorthand properties using `inherit` being omitted (#100)
- Added support for `conic-gradient` (#101)

# 0.16.4

Expand Down
10 changes: 10 additions & 0 deletions src/AngleSharp.Css.Tests/Library/StringRepresentation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,15 @@ public void ShorthandBorderInheritPropertiesShouldBeIncluded_Issue100()
var css = styleSheet.ToCss();
Assert.AreEqual("#x div { border: inherit }", css);
}

[Test]
public void ConicGradientNotParsedCorrectly_Issue101()
{
var html = @"<style>div { background: conic-gradient(red, yellow, green); }</style>";
var dom = ParseDocument(html);
var styleSheet = dom.StyleSheets[0] as ICssStyleSheet;
var css = styleSheet.ToCss();
Assert.AreEqual("div { background: conic-gradient(rgba(255, 0, 0, 1), rgba(255, 255, 0, 1), rgba(0, 128, 0, 1)) }", css);
}
}
}
10 changes: 10 additions & 0 deletions src/AngleSharp.Css/Constants/FunctionNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ public static class FunctionNames
/// </summary>
public static readonly String RadialGradient = "radial-gradient";

/// <summary>
/// The conic-gradient function.
/// </summary>
public static readonly String ConicGradient = "conic-gradient";

/// <summary>
/// The repeating-linear-gradient function.
/// </summary>
Expand All @@ -97,6 +102,11 @@ public static class FunctionNames
/// </summary>
public static readonly String RepeatingRadialGradient = "repeating-radial-gradient";

/// <summary>
/// The repeating-conic-gradient function.
/// </summary>
public static readonly String RepeatingConicGradient = "repeating-conic-gradient";

/// <summary>
/// The image function.
/// </summary>
Expand Down
70 changes: 70 additions & 0 deletions src/AngleSharp.Css/Parser/Micro/GradientParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ static class GradientParser
{ FunctionNames.RepeatingLinearGradient, ParseRepeatingLinearGradient },
{ FunctionNames.RadialGradient, ParseRadialGradient },
{ FunctionNames.RepeatingRadialGradient, ParseRepeatingRadialGradient },
{ FunctionNames.ConicGradient, ParseConicGradient },
{ FunctionNames.RepeatingConicGradient, ParseRepeatingConicGradient },
};

public static ICssGradientFunctionValue ParseGradient(this StringSource source)
Expand Down Expand Up @@ -128,6 +130,74 @@ private static ICssGradientFunctionValue ParseRadialGradient(StringSource source
return null;
}

private static ICssGradientFunctionValue ParseConicGradient(StringSource source)
{
return ParseConicGradient(source, false);
}

private static ICssGradientFunctionValue ParseRepeatingConicGradient(StringSource source)
{
return ParseConicGradient(source, true);
}

/// <summary>
/// Parses a conic gradient.
/// https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/conic-gradient
/// </summary>
private static ICssGradientFunctionValue ParseConicGradient(StringSource source, Boolean repeating)
{
ICssValue angle = null;
ICssValue center = null;

source.SkipSpacesAndComments();

if (source.IsIdentifier(CssKeywords.From))
{
source.SkipSpacesAndComments();
angle = source.ParseAngleOrCalc();

if (angle == null)
{
return null;
}

source.SkipSpacesAndComments();
}

if (source.IsIdentifier(CssKeywords.At))
{
source.SkipSpacesAndComments();
center = source.ParsePoint();

if (center == null)
{
return null;
}
}

if (angle != null || center != null)
{
var current = source.SkipSpacesAndComments();

if (current != Symbols.Comma)
{
return null;
}

source.SkipCurrentAndSpaces();
}

var stops = ParseGradientStops(source);

if (stops != null && source.Current == Symbols.RoundBracketClose)
{
source.SkipCurrentAndSpaces();
return new CssConicGradientValue(angle, center, stops, repeating);
}

return null;
}

private static CssGradientStopValue[] ParseGradientStops(StringSource source)
{
var stops = new List<CssGradientStopValue>();
Expand Down
125 changes: 125 additions & 0 deletions src/AngleSharp.Css/Values/Functions/CssConicGradientValue.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
namespace AngleSharp.Css.Values
{
using AngleSharp.Css.Dom;
using AngleSharp.Text;
using System;
using System.Linq;

/// <summary>
/// Represents a linear gradient:
/// https://drafts.csswg.org/css-images-4/#conic-gradients
/// </summary>
sealed class CssConicGradientValue : ICssGradientFunctionValue
{
#region Fields

private readonly CssGradientStopValue[] _stops;
private readonly ICssValue _center;
private readonly ICssValue _angle;
private readonly Boolean _repeating;

#endregion

#region ctor

/// <summary>
/// Creates a new conic gradient.
/// </summary>
/// <param name="angle">The angle of the conic gradient.</param>
/// <param name="center">The center to use.</param>
/// <param name="stops">The stops to use.</param>
/// <param name="repeating">Indicates if the gradient is repeating.</param>
public CssConicGradientValue(ICssValue angle, ICssValue center, CssGradientStopValue[] stops, Boolean repeating = false)
{
_stops = stops;
_center = center;
_angle = angle;
_repeating = repeating;
}

#endregion

#region Properties

/// <summary>
/// Gets the name of the function.
/// </summary>
public String Name => _repeating ? FunctionNames.RepeatingConicGradient : FunctionNames.ConicGradient;

/// <summary>
/// Gets the arguments.
/// </summary>
public ICssValue[] Arguments
{
get
{
var args = _stops.Cast<ICssValue>().ToList();

if (_center != null)
{
args.Insert(0, _center);
}

if (_angle != null)
{
args.Insert(0, _angle);
}

return args.ToArray();
}
}

/// <summary>
/// Gets the CSS text representation.
/// </summary>
public String CssText
{
get
{
var defaultAngle = _angle as Angle?;
var defaultPosition = _center as Point?;
var offset = (defaultAngle.HasValue ? 1 : 0) + (defaultPosition.HasValue ? 1 : 0);
var args = new String[_stops.Length + offset];

if (defaultAngle.HasValue)
{
args[0] = $"from {defaultAngle.Value.CssText}";
}

if (defaultPosition.HasValue)
{
args[offset - 1] = $"at {defaultPosition.Value.CssText}";
}

for (var i = 0; i < _stops.Length; i++)
{
args[offset++] = _stops[i].CssText;
}

return Name.CssFunction(String.Join(", ", args));
}
}

/// <summary>
/// Gets the angle of the conic gradient.
/// </summary>
public ICssValue Angle => _angle ?? Values.Angle.Half;

/// <summary>
/// Gets the position of the conic gradient.
/// </summary>
public ICssValue Center => _center ?? Point.Center;

/// <summary>
/// Gets all stops.
/// </summary>
public CssGradientStopValue[] Stops => _stops;

/// <summary>
/// Gets if the gradient is repeating.
/// </summary>
public Boolean IsRepeating => _repeating;

#endregion
}
}

0 comments on commit 46b9c9a

Please sign in to comment.