Browse Source

Added path clipping infrastructure. Got Skia implementation working.

pull/544/head
Jeremy Koritzinsky 11 years ago
parent
commit
7969504431
  1. 21
      src/Avalonia.SceneGraph/Media/DrawingContext.cs
  2. 10
      src/Avalonia.SceneGraph/Media/IDrawingContext.cs
  3. 27
      src/Avalonia.SceneGraph/Media/PathMarkupParser.cs
  4. 1
      src/Avalonia.SceneGraph/Rendering/RendererMixin.cs
  5. 15
      src/Avalonia.SceneGraph/Visual.cs
  6. 5
      src/Avalonia.SceneGraph/VisualTree/IVisual.cs
  7. 11
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs

21
src/Avalonia.SceneGraph/Media/DrawingContext.cs

@ -127,7 +127,8 @@ namespace Avalonia.Media
Matrix,
Opacity,
Clip,
MatrixContainer
MatrixContainer,
GeometryClip
}
public PushedState(DrawingContext context, PushedStateType type, Matrix matrix = default(Matrix))
@ -149,10 +150,12 @@ namespace Avalonia.Media
_context._states.Pop();
if (_type == PushedStateType.Matrix)
_context.CurrentTransform = _matrix;
else if(_type == PushedStateType.Clip)
else if (_type == PushedStateType.Clip)
_context._impl.PopClip();
else if(_type == PushedStateType.Opacity)
else if (_type == PushedStateType.Opacity)
_context._impl.PopOpacity();
else if (_type == PushedStateType.GeometryClip)
_context._impl.PopGeometryClip();
else if (_type == PushedStateType.MatrixContainer)
{
var cont = _context._transformContainers.Pop();
@ -174,6 +177,18 @@ namespace Avalonia.Media
return new PushedState(this, PushedState.PushedStateType.Clip);
}
/// <summary>
/// Pushes a clip geometry.
/// </summary>
/// <param name="clip">The clip geometry.</param>
/// <returns>A disposable used to undo the clip geometry.</returns>
public PushedState PushGeometryClip(Geometry clip)
{
Contract.Requires<ArgumentNullException>(clip != null);
_impl.PushGeometryClip(clip);
return new PushedState(this, PushedState.PushedStateType.GeometryClip);
}
/// <summary>
/// Pushes an opacity value.
/// </summary>

10
src/Avalonia.SceneGraph/Media/IDrawingContext.cs

@ -69,7 +69,6 @@ namespace Avalonia.Media
/// Pushes a clip rectange.
/// </summary>
/// <param name="clip">The clip rectangle.</param>
/// <returns>A disposable used to undo the clip rectangle.</returns>
void PushClip(Rect clip);
void PopClip();
@ -78,9 +77,16 @@ namespace Avalonia.Media
/// Pushes an opacity value.
/// </summary>
/// <param name="opacity">The opacity.</param>
/// <returns>A disposable used to undo the opacity.</returns>
void PushOpacity(double opacity);
void PopOpacity();
/// <summary>
/// Pushes a clip geometry.
/// </summary>
/// <param name="clip">The clip geometry.</param>
void PushGeometryClip(Geometry clip);
void PopGeometryClip();
}
}

27
src/Avalonia.SceneGraph/Media/PathMarkupParser.cs

@ -34,6 +34,12 @@ namespace Avalonia.Media
{ 'z', Command.Close },
};
private static readonly Dictionary<char, FillRule> FillRules = new Dictionary<char, FillRule>
{
{'0', FillRule.EvenOdd },
{'1', FillRule.NonZero }
};
private StreamGeometry _geometry;
private readonly StreamGeometryContext _context;
@ -90,8 +96,7 @@ namespace Avalonia.Media
switch (command)
{
case Command.FillRule:
// TODO: Implement.
reader.Read();
_context.SetFillRule(ReadFillRule(reader));
break;
case Command.Move:
@ -226,6 +231,24 @@ namespace Avalonia.Media
}
}
private static FillRule ReadFillRule(StringReader reader)
{
int i = reader.Read();
if (i == -1)
{
throw new InvalidDataException("Invalid fill rule");
}
char c = (char)i;
FillRule rule;
if (!FillRules.TryGetValue(c, out rule))
{
throw new InvalidDataException("Invalid fill rule");
}
return rule;
}
private static double ReadDouble(StringReader reader)
{
ReadWhitespace(reader);

1
src/Avalonia.SceneGraph/Rendering/RendererMixin.cs

@ -119,6 +119,7 @@ namespace Avalonia.Rendering
using (context.PushPostTransform(m))
using (context.PushOpacity(opacity))
using (clipToBounds ? context.PushClip(bounds) : default(DrawingContext.PushedState))
using (visual.Clip != null ? context.PushGeometryClip(visual.Clip) : default(DrawingContext.PushedState))
using (context.PushTransformContainer())
{
visual.Render(context);

15
src/Avalonia.SceneGraph/Visual.cs

@ -39,6 +39,12 @@ namespace Avalonia
public static readonly StyledProperty<bool> ClipToBoundsProperty =
AvaloniaProperty.Register<Visual, bool>(nameof(ClipToBounds));
/// <summary>
/// Defines the <see cref="Clip"/> property.
/// </summary>
public static readonly StyledProperty<Geometry> ClipProperty =
AvaloniaProperty.Register<Visual, Geometry>(nameof(Clip));
/// <summary>
/// Defines the <see cref="IsVisibleProperty"/> property.
/// </summary>
@ -127,6 +133,15 @@ namespace Avalonia
set { SetValue(ClipToBoundsProperty, value); }
}
/// <summary>
/// Gets or sets the geometry clip for this visual.
/// </summary>
public Geometry Clip
{
get { return GetValue(ClipProperty); }
set { SetValue(ClipProperty, value); }
}
/// <summary>
/// Gets a value indicating whether this scene graph node and all its parents are visible.
/// </summary>

5
src/Avalonia.SceneGraph/VisualTree/IVisual.cs

@ -41,6 +41,11 @@ namespace Avalonia.VisualTree
/// </summary>
bool ClipToBounds { get; set; }
/// <summary>
/// Gets or sets the geometry clip for this visual.
/// </summary>
Geometry Clip { get; set; }
/// <summary>
/// Gets a value indicating whether this scene graph node is attached to a visual root.
/// </summary>

11
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@ -288,6 +288,17 @@ namespace Avalonia.Skia
{
}
public void PushGeometryClip(Geometry clip)
{
Canvas.Save();
Canvas.ClipPath(((StreamGeometryImpl)clip.PlatformImpl).EffectivePath);
}
public void PopGeometryClip()
{
Canvas.Restore();
}
private Matrix _currentTransform = Matrix.Identity;
public Matrix Transform

Loading…
Cancel
Save