|
|
|
@ -21,7 +21,10 @@ namespace Avalonia.Media |
|
|
|
{ 'L', Command.Line }, |
|
|
|
{ 'H', Command.HorizontalLine }, |
|
|
|
{ 'V', Command.VerticalLine }, |
|
|
|
{ 'Q', Command.QuadraticBezierCurve }, |
|
|
|
{ 'T', Command.SmoothQuadraticBezierCurve }, |
|
|
|
{ 'C', Command.CubicBezierCurve }, |
|
|
|
{ 'S', Command.SmoothCubicBezierCurve }, |
|
|
|
{ 'A', Command.Arc }, |
|
|
|
{ 'Z', Command.Close }, |
|
|
|
}; |
|
|
|
@ -55,6 +58,9 @@ namespace Avalonia.Media |
|
|
|
HorizontalLine, |
|
|
|
VerticalLine, |
|
|
|
CubicBezierCurve, |
|
|
|
QuadraticBezierCurve, |
|
|
|
SmoothCubicBezierCurve, |
|
|
|
SmoothQuadraticBezierCurve, |
|
|
|
Arc, |
|
|
|
Close, |
|
|
|
} |
|
|
|
@ -71,7 +77,8 @@ namespace Avalonia.Media |
|
|
|
{ |
|
|
|
Command command = Command.None; |
|
|
|
Point point = new Point(); |
|
|
|
bool relative = false; |
|
|
|
bool relative = false; |
|
|
|
Point? previousControlPoint = null; |
|
|
|
|
|
|
|
while (ReadCommand(reader, ref command, ref relative)) |
|
|
|
{ |
|
|
|
@ -79,6 +86,7 @@ namespace Avalonia.Media |
|
|
|
{ |
|
|
|
case Command.FillRule: |
|
|
|
_context.SetFillRule(ReadFillRule(reader)); |
|
|
|
previousControlPoint = null; |
|
|
|
break; |
|
|
|
|
|
|
|
case Command.Move: |
|
|
|
@ -90,11 +98,13 @@ namespace Avalonia.Media |
|
|
|
point = ReadPoint(reader, point, relative); |
|
|
|
_context.BeginFigure(point, true); |
|
|
|
openFigure = true; |
|
|
|
previousControlPoint = null; |
|
|
|
break; |
|
|
|
|
|
|
|
case Command.Line: |
|
|
|
point = ReadPoint(reader, point, relative); |
|
|
|
_context.LineTo(point); |
|
|
|
previousControlPoint = null; |
|
|
|
break; |
|
|
|
|
|
|
|
case Command.HorizontalLine: |
|
|
|
@ -108,6 +118,7 @@ namespace Avalonia.Media |
|
|
|
} |
|
|
|
|
|
|
|
_context.LineTo(point); |
|
|
|
previousControlPoint = null; |
|
|
|
break; |
|
|
|
|
|
|
|
case Command.VerticalLine: |
|
|
|
@ -121,18 +132,57 @@ namespace Avalonia.Media |
|
|
|
} |
|
|
|
|
|
|
|
_context.LineTo(point); |
|
|
|
previousControlPoint = null; |
|
|
|
break; |
|
|
|
|
|
|
|
case Command.QuadraticBezierCurve: |
|
|
|
{ |
|
|
|
Point handle = ReadPoint(reader, point, relative); |
|
|
|
previousControlPoint = handle; |
|
|
|
ReadSeparator(reader); |
|
|
|
point = ReadPoint(reader, point, relative); |
|
|
|
_context.QuadraticBezierTo(handle, point); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
case Command.SmoothQuadraticBezierCurve: |
|
|
|
{ |
|
|
|
Point end = ReadPoint(reader, point, relative); |
|
|
|
|
|
|
|
if(previousControlPoint != null) |
|
|
|
previousControlPoint = MirrorControlPoint((Point)previousControlPoint, point); |
|
|
|
|
|
|
|
_context.QuadraticBezierTo(previousControlPoint ?? point, end); |
|
|
|
point = end; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
case Command.CubicBezierCurve: |
|
|
|
{ |
|
|
|
Point point1 = ReadPoint(reader, point, relative); |
|
|
|
ReadSeparator(reader); |
|
|
|
Point point2 = ReadPoint(reader, point, relative); |
|
|
|
previousControlPoint = point2; |
|
|
|
ReadSeparator(reader); |
|
|
|
point = ReadPoint(reader, point, relative); |
|
|
|
_context.CubicBezierTo(point1, point2, point); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
case Command.SmoothCubicBezierCurve: |
|
|
|
{ |
|
|
|
Point point2 = ReadPoint(reader, point, relative); |
|
|
|
ReadSeparator(reader); |
|
|
|
Point end = ReadPoint(reader, point, relative); |
|
|
|
|
|
|
|
if(previousControlPoint != null) |
|
|
|
previousControlPoint = MirrorControlPoint((Point)previousControlPoint, point); |
|
|
|
|
|
|
|
_context.CubicBezierTo(previousControlPoint ?? point, point2, end); |
|
|
|
previousControlPoint = point2; |
|
|
|
point = end; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
case Command.Arc: |
|
|
|
{ |
|
|
|
@ -147,12 +197,14 @@ namespace Avalonia.Media |
|
|
|
point = ReadPoint(reader, point, relative); |
|
|
|
|
|
|
|
_context.ArcTo(point, size, rotationAngle, isLargeArc, sweepDirection); |
|
|
|
previousControlPoint = null; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
case Command.Close: |
|
|
|
_context.EndFigure(true); |
|
|
|
openFigure = false; |
|
|
|
previousControlPoint = null; |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
@ -167,6 +219,14 @@ namespace Avalonia.Media |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private Point MirrorControlPoint(Point controlPoint, Point center) |
|
|
|
{ |
|
|
|
Point dir = (controlPoint - center); |
|
|
|
double xOffset = center.X - controlPoint.X, yOffset = center.Y - controlPoint.Y; |
|
|
|
// return new Point(center.X - xOffset, center.Y - yOffset);
|
|
|
|
return center + -dir; |
|
|
|
} |
|
|
|
|
|
|
|
private static bool ReadCommand( |
|
|
|
StringReader reader, |
|
|
|
ref Command command, |
|
|
|
@ -243,6 +303,9 @@ namespace Avalonia.Media |
|
|
|
(c == 'E' && !readExponent) || |
|
|
|
char.IsDigit(c)) |
|
|
|
{ |
|
|
|
if (b.Length != 0 && !readExponent && c == '-') |
|
|
|
break; |
|
|
|
|
|
|
|
b.Append(c); |
|
|
|
reader.Read(); |
|
|
|
|
|
|
|
|