This commit is contained in:
Bret Johnson 2019-09-02 14:09:05 -04:00
Родитель 140953b4e8
Коммит 31af9445d5
10 изменённых файлов: 150 добавлений и 39 удалений

Просмотреть файл

@ -129,6 +129,7 @@ namespace XGraphics.Renderer.Skia
return skiaPathFigures;
}
private void AddPathSegmentToSkiaPath(SKPath skPath, IPathSegment pathSegment)
{
if (pathSegment is IBezierSegment bezierSegment)
@ -136,6 +137,29 @@ namespace XGraphics.Renderer.Skia
(float)bezierSegment.Point1.X, (float)bezierSegment.Point1.Y,
(float)bezierSegment.Point2.X, (float)bezierSegment.Point2.Y,
(float)bezierSegment.Point3.X, (float)bezierSegment.Point3.Y);
else if (pathSegment is IPolyBezierSegment polyBezierSegment)
{
List<Point> points = new List<Point>();
foreach (Point point in polyBezierSegment.Points)
points.Add(point);
if (points.Count % 3 != 0)
throw new InvalidOperationException($"IPolyBezerSegment contains {points.Count} points, which isn't a multiple of 3");
for (int i = 0; i < points.Count; )
{
var point1 = points[i + 0];
var point2 = points[i + 1];
var point3 = points[i + 2];
skPath.CubicTo(
(float)point1.X, (float)point1.Y,
(float)point2.X, (float)point2.Y,
(float)point3.X, (float)point3.Y);
i += 3;
}
}
else if (pathSegment is ILineSegment lineSegment)
skPath.LineTo((float) lineSegment.Point.X, (float) lineSegment.Point.Y);
else if (pathSegment is IQuadraticBezierSegment quadraticBezierSegment)
@ -203,7 +227,7 @@ namespace XGraphics.Renderer.Skia
if (fill != null && allowFill)
{
using SKPaint paint = new SKPaint { Style = SKPaintStyle.Fill, IsAntialias = true };
InitSkiaPaintForBrush(paint, fill);
InitSkiaPaintForBrush(paint, fill, shape);
skCanvas.DrawPath(skiaPath, paint);
}
@ -211,25 +235,66 @@ namespace XGraphics.Renderer.Skia
if (stroke != null)
{
using SKPaint paint = new SKPaint { Style = SKPaintStyle.Stroke, IsAntialias = true };
InitSkiaPaintForBrush(paint, stroke);
InitSkiaPaintForBrush(paint, stroke, shape);
paint.StrokeWidth = (int)shape.StrokeThickness;
skCanvas.DrawPath(skiaPath, paint);
}
}
public static void InitSkiaPaintForBrush(SKPaint paint, IBrush brush)
public static void InitSkiaPaintForBrush(SKPaint paint, IBrush brush, IShape shape)
{
if (brush is ISolidColorBrush solidColorBrush)
paint.Color = ToSkiaColor(solidColorBrush.Color);
else if (brush is IGradientBrush gradientBrush)
paint.Shader = ToSkiaShader(gradientBrush, shape);
else throw new InvalidOperationException($"Brush type {brush.GetType()} isn't currently supported");
}
public static SKColor ToSkiaColor(Color color) =>
new SKColor(color.R, color.G, color.B, color.A);
public static SKColor ToSkiaColor(Color color) => new SKColor(color.R, color.G, color.B, color.A);
public static SKPoint ToSkiaPoint(Point point) =>
new SKPoint((float) point.X, (float) point.Y);
public static SKShader ToSkiaShader(IGradientBrush gradientBrush, IShape shape)
{
SKShaderTileMode tileMode = gradientBrush.SpreadMethod switch
{
GradientSpreadMethod.Pad => SKShaderTileMode.Clamp,
GradientSpreadMethod.Reflect => SKShaderTileMode.Mirror,
GradientSpreadMethod.Repeat => SKShaderTileMode.Repeat,
_ => throw new InvalidOperationException($"Unknown GradientSpreadmethod value {gradientBrush.SpreadMethod}")
};
List<SKColor> skiaColors = new List<SKColor>();
List<float> skiaColorPositions = new List<float>();
foreach (IGradientStop gradientStop in gradientBrush.GradientStops)
{
skiaColors.Add(ToSkiaColor(gradientStop.Color));
skiaColorPositions.Add((float)gradientStop.Offset);
}
if (gradientBrush is ILinearGradientBrush linearGradientBrush)
{
SKPoint skiaStartPoint = new SKPoint(
(float)(shape.Left + linearGradientBrush.StartPoint.X * shape.Width),
(float)(shape.Top + linearGradientBrush.StartPoint.Y * shape.Height));
SKPoint skiaEndPoint = new SKPoint(
(float)(shape.Left + linearGradientBrush.EndPoint.X * shape.Width),
(float)(shape.Top + linearGradientBrush.EndPoint.Y * shape.Height));
return SKShader.CreateLinearGradient(skiaStartPoint, skiaEndPoint, skiaColors.ToArray(), skiaColorPositions.ToArray(), tileMode);
}
else if (gradientBrush is IRadialGradientBrush radialGradientBrush)
{
SKPoint skiaCenterPoint = new SKPoint(
(float)(shape.Left + radialGradientBrush.Center.X * shape.Width),
(float)(shape.Top + radialGradientBrush.Center.Y * shape.Height));
float radius = (float)(radialGradientBrush.RadiusX * shape.Width);
return SKShader.CreateRadialGradient(skiaCenterPoint, radius, skiaColors.ToArray(), skiaColorPositions.ToArray(), tileMode);
}
else throw new InvalidOperationException($"GradientBrush type {gradientBrush.GetType()} is unknown");
}
public static SKPoint ToSkiaPoint(Point point) => new SKPoint((float) point.X, (float) point.Y);
public static void AddSkiaPoints(IEnumerable<Point> points, List<SKPoint> skiaPoints)
{

Просмотреть файл

@ -495,7 +495,7 @@ namespace XGraphics.DataModelGenerator
private static bool IsEnumType(string typeName)
{
return typeName == "SweepDirection" || typeName == "FillRule";
return typeName == "SweepDirection" || typeName == "FillRule" || typeName == "GradientSpreadMethod";
}
private static bool IsPointType(TypeSyntax type)
@ -536,7 +536,23 @@ namespace XGraphics.DataModelGenerator
if (firstArgument == null)
throw new UserViewableException($"Property {modelProperty.Identifier.Text} should have an argument for the [ModelDefaultValue] attribute");
return firstArgument.Expression;
ExpressionSyntax defaultExpression = firstArgument.Expression;
if (defaultExpression is LiteralExpressionSyntax literalExpression && literalExpression.Token.IsKind(SyntaxKind.StringLiteralToken))
{
string literalExpressionString = literalExpression.Token.ToString();
if (literalExpressionString == "\"0.5,0.5\"")
defaultExpression =
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("Wrapper"),
IdentifierName("Point")),
IdentifierName("CenterDefault"));
else throw new UserViewableException($"Unknown string literal based default value: {literalExpressionString}");
}
return defaultExpression;
}
}

Просмотреть файл

@ -6,12 +6,10 @@ namespace XGraphics.WPF.Brushes
{
public class RadialGradientBrush : GradientBrush, IRadialGradientBrush
{
public static readonly DependencyProperty CenterProperty = PropertyUtils.Create(nameof(Center), typeof(Wrapper.Point), typeof(RadialGradientBrush), PropertyUtils.DefaultPoint);
public static readonly DependencyProperty GraidentOriginProperty = PropertyUtils.Create(nameof(GraidentOrigin), typeof(Wrapper.Point), typeof(RadialGradientBrush), PropertyUtils.DefaultPoint);
public static readonly DependencyProperty CenterProperty = PropertyUtils.Create(nameof(Center), typeof(Wrapper.Point), typeof(RadialGradientBrush), Wrapper.Point.CenterDefault);
public static readonly DependencyProperty GraidentOriginProperty = PropertyUtils.Create(nameof(GraidentOrigin), typeof(Wrapper.Point), typeof(RadialGradientBrush), Wrapper.Point.CenterDefault);
public static readonly DependencyProperty RadiusXProperty = PropertyUtils.Create(nameof(RadiusX), typeof(double), typeof(RadialGradientBrush), 0.5);
public static readonly DependencyProperty RadiusYProperty = PropertyUtils.Create(nameof(RadiusY), typeof(double), typeof(RadialGradientBrush), 0.5);
// The default value is 0.5, 0.5
Point IRadialGradientBrush.Center => Center.WrappedPoint;
public Wrapper.Point Center
{
@ -19,7 +17,6 @@ namespace XGraphics.WPF.Brushes
set => SetValue(CenterProperty, value);
}
// The default value is 0.5, 0.5
Point IRadialGradientBrush.GraidentOrigin => GraidentOrigin.WrappedPoint;
public Wrapper.Point GraidentOrigin
{
@ -32,11 +29,5 @@ namespace XGraphics.WPF.Brushes
get => (double)GetValue(RadiusXProperty);
set => SetValue(RadiusXProperty, value);
}
public double RadiusY
{
get => (double)GetValue(RadiusYProperty);
set => SetValue(RadiusYProperty, value);
}
}
}

Просмотреть файл

@ -12,8 +12,7 @@ namespace XGraphics.WPF.Converters
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context,
CultureInfo culture, object valueObject)
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object valueObject)
{
if (!(valueObject is string value))
throw new InvalidOperationException($"Cannot convert from type {valueObject.GetType()}");

Просмотреть файл

@ -0,0 +1,25 @@
using System;
using System.ComponentModel;
using System.Globalization;
using XGraphics.Converters;
namespace XGraphics.WPF.Converters
{
public class PointTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => sourceType == typeof(string);
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object valueObject)
{
if (!(valueObject is string value))
throw new InvalidOperationException($"Cannot convert from type {valueObject.GetType()}");
return new Wrapper.Point(PointConverter.ConvertFromString(value));
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) => false;
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) =>
throw new InvalidOperationException($"ConvertTo isn't currently supported");
}
}

Просмотреть файл

@ -1,11 +1,15 @@
using XGraphicsPoint = XGraphics.Point;
using System.ComponentModel;
using XGraphics.WPF.Converters;
using XGraphicsPoint = XGraphics.Point;
namespace XGraphics.WPF.Wrapper
{
[TypeConverter(typeof(PointTypeConverter))]
public struct Point
{
public static readonly Point Default = new Point(XGraphicsPoint.Default);
public static readonly Point CenterDefault = new Point(XGraphicsPoint.CenterDefault);
public XGraphicsPoint WrappedPoint { get; }

Просмотреть файл

@ -5,12 +5,10 @@ namespace XGraphics.XamarinForms.Brushes
{
public class RadialGradientBrush : GradientBrush, IRadialGradientBrush
{
public static readonly BindableProperty CenterProperty = PropertyUtils.Create(nameof(Center), typeof(Wrapper.Point), typeof(RadialGradientBrush), PropertyUtils.DefaultPoint);
public static readonly BindableProperty GraidentOriginProperty = PropertyUtils.Create(nameof(GraidentOrigin), typeof(Wrapper.Point), typeof(RadialGradientBrush), PropertyUtils.DefaultPoint);
public static readonly BindableProperty CenterProperty = PropertyUtils.Create(nameof(Center), typeof(Wrapper.Point), typeof(RadialGradientBrush), Wrapper.Point.CenterDefault);
public static readonly BindableProperty GraidentOriginProperty = PropertyUtils.Create(nameof(GraidentOrigin), typeof(Wrapper.Point), typeof(RadialGradientBrush), Wrapper.Point.CenterDefault);
public static readonly BindableProperty RadiusXProperty = PropertyUtils.Create(nameof(RadiusX), typeof(double), typeof(RadialGradientBrush), 0.5);
public static readonly BindableProperty RadiusYProperty = PropertyUtils.Create(nameof(RadiusY), typeof(double), typeof(RadialGradientBrush), 0.5);
// The default value is 0.5, 0.5
Point IRadialGradientBrush.Center => Center.WrappedPoint;
public Wrapper.Point Center
{
@ -18,7 +16,6 @@ namespace XGraphics.XamarinForms.Brushes
set => SetValue(CenterProperty, value);
}
// The default value is 0.5, 0.5
Point IRadialGradientBrush.GraidentOrigin => GraidentOrigin.WrappedPoint;
public Wrapper.Point GraidentOrigin
{
@ -31,11 +28,5 @@ namespace XGraphics.XamarinForms.Brushes
get => (double)GetValue(RadiusXProperty);
set => SetValue(RadiusXProperty, value);
}
public double RadiusY
{
get => (double)GetValue(RadiusYProperty);
set => SetValue(RadiusYProperty, value);
}
}
}

Просмотреть файл

@ -3,16 +3,13 @@
[GraphicsModelObject]
public interface IRadialGradientBrush : IGradientBrush
{
// The default value is 0.5, 0.5
[ModelDefaultValue("0.5,0.5")]
Point Center { get; }
// The default value is 0.5, 0.5
[ModelDefaultValue("0.5,0.5")]
Point GraidentOrigin { get; }
[ModelDefaultValue(0.5)]
double RadiusX { get; }
[ModelDefaultValue(0.5)]
double RadiusY { get; }
}
}

Просмотреть файл

@ -0,0 +1,22 @@
using System;
using System.Globalization;
namespace XGraphics.Converters
{
public static class PointConverter
{
public static Point ConvertFromString(string value)
{
if (value != null)
{
double x, y;
string[] xy = value.Split(',');
if (xy.Length == 2 && double.TryParse(xy[0], NumberStyles.Number, CultureInfo.InvariantCulture, out x) && double.TryParse(xy[1], NumberStyles.Number, CultureInfo.InvariantCulture, out y))
return new Point(x, y);
}
throw new InvalidOperationException(string.Format("Cannot convert \"{0}\" into {1}", value, typeof(Point)));
}
}
}

Просмотреть файл

@ -3,6 +3,7 @@
public struct Point
{
public static readonly Point Default = new Point(0, 0);
public static readonly Point CenterDefault = new Point(0.5, 0.5);
public Point(double x, double y)