Browse Source

Fixed `Path_Tick_Scaled`, `Path_Tick_Scaled_Stroke_8px` and `Path_Expander_With_Border` for Skia

pull/398/head
Nikita Tsukanov 10 years ago
parent
commit
a74e9b3ff7
  1. 16
      src/Skia/Perspex.Skia/DrawingContextImpl.cs
  2. 35
      src/Skia/Perspex.Skia/MethodTable.cs
  3. 59
      src/Skia/Perspex.Skia/PerspexHandleHolder.cs
  4. 40
      src/Skia/Perspex.Skia/StreamGeometryImpl.cs
  5. 12
      tests/Perspex.RenderTests/Shapes/PathTests.cs

16
src/Skia/Perspex.Skia/DrawingContextImpl.cs

@ -37,18 +37,13 @@ namespace Perspex.Skia
public void DrawGeometry(Brush brush, Pen pen, Geometry geometry) public void DrawGeometry(Brush brush, Pen pen, Geometry geometry)
{ {
var impl = ((StreamGeometryImpl) geometry.PlatformImpl); var impl = ((StreamGeometryImpl) geometry.PlatformImpl);
var oldTransform = Transform;
if (!impl.Transform.IsIdentity)
Transform = impl.Transform*Transform;
var size = geometry.Bounds.Size; var size = geometry.Bounds.Size;
using(var fill = brush!=null?CreateBrush(brush, size):null) using(var fill = brush!=null?CreateBrush(brush, size):null)
using (var stroke = pen?.Brush != null ? CreateBrush(pen, size) : null) using (var stroke = pen?.Brush != null ? CreateBrush(pen, size) : null)
{ {
MethodTable.Instance.DrawGeometry(Handle, impl.Path.Handle, fill != null ? fill.Brush : null, MethodTable.Instance.DrawGeometry(Handle, impl.EffectivePath, fill != null ? fill.Brush : null,
stroke != null ? stroke.Brush : null, impl.FillRule == FillRule.EvenOdd); stroke != null ? stroke.Brush : null, impl.FillRule == FillRule.EvenOdd);
} }
Transform = oldTransform;
} }
unsafe NativeBrushContainer CreateBrush(Brush brush, Size targetSize) unsafe NativeBrushContainer CreateBrush(Brush brush, Size targetSize)
@ -196,14 +191,7 @@ namespace Perspex.Skia
if(_currentTransform == value) if(_currentTransform == value)
return; return;
_currentTransform = value; _currentTransform = value;
_fmatrix[0] = (float)value.M11; MethodTable.Instance.SetTransform(Handle, value);
_fmatrix[1] = (float)value.M21;
_fmatrix[2] = (float)value.M31;
_fmatrix[3] = (float)value.M12;
_fmatrix[4] = (float)value.M22;
_fmatrix[5] = (float)value.M32;
MethodTable.Instance.SetTransform(Handle, _fmatrix);
} }
} }
} }

35
src/Skia/Perspex.Skia/MethodTable.cs

@ -47,9 +47,9 @@ namespace Perspex.Skia
public _PopClip PopClip; public _PopClip PopClip;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void _SetTransform(IntPtr ctx, float[] matrix6); public delegate void _SetTransform(IntPtr ctx, void* matrix6);
public _SetTransform SetTransform; public _SetTransform SetTransformNative;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void _DrawLine(IntPtr ctx, void* brush, float x1, float y1, float x2, float y2); public delegate void _DrawLine(IntPtr ctx, void* brush, float x1, float y1, float x2, float y2);
@ -66,6 +66,11 @@ namespace Perspex.Skia
public _DisposePath DisposePath; public _DisposePath DisposePath;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate IntPtr _TransformPath(IntPtr path, void* matrix6);
public _TransformPath TransformPathNative;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void _DrawGeometry(IntPtr ctx, IntPtr path, void* fill, void* stroke, bool useEvenOdd); public delegate void _DrawGeometry(IntPtr ctx, IntPtr path, void* fill, void* stroke, bool useEvenOdd);
@ -185,10 +190,34 @@ namespace Perspex.Skia
typeof (_RebuildFormattedText), typeof (_RebuildFormattedText),
typeof (_DestroyFormattedText), typeof (_DestroyFormattedText),
typeof (_DrawFormattedText), typeof (_DrawFormattedText),
typeof (_SetOption) typeof (_SetOption),
typeof (_TransformPath)
}; };
void ConvertMatrix(Matrix value, float* target)
{
target[0] = (float)value.M11;
target[1] = (float)value.M21;
target[2] = (float)value.M31;
target[3] = (float)value.M12;
target[4] = (float)value.M22;
target[5] = (float)value.M32;
}
public unsafe IntPtr TransformPath(IntPtr path, Matrix matrix)
{
var tmp = stackalloc float[6];
ConvertMatrix(matrix, tmp);
return TransformPathNative(path, tmp);
}
public unsafe void SetTransform(IntPtr ctx, Matrix matrix)
{
var tmp = stackalloc float[6];
ConvertMatrix(matrix, tmp);
SetTransformNative(ctx, tmp);
}
protected MethodTable(IntPtr methodTable) protected MethodTable(IntPtr methodTable)
{ {

59
src/Skia/Perspex.Skia/PerspexHandleHolder.cs

@ -44,4 +44,63 @@ namespace Perspex.Skia
Dispose(); Dispose();
} }
} }
class RefCountable<T> : IDisposable where T : PerspexHandleHolder
{
class Shared
{
public readonly T Target;
private int _refCount = 1;
public Shared(T target)
{
Target = target;
}
public void AddRef() => _refCount++;
public void Release()
{
_refCount--;
if (_refCount <= 0)
Target.Dispose();
}
}
public bool IsDisposed => _shared == null;
private Shared _shared;
public void CheckDisposed()
{
if (IsDisposed)
throw new ObjectDisposedException(GetType().FullName);
}
public IntPtr Handle
{
get
{
CheckDisposed();
return _shared.Target.Handle;
}
}
public RefCountable(T handle)
{
_shared = new Shared(handle);
}
public RefCountable(RefCountable<T> other)
{
other._shared.Target.CheckDisposed();
other._shared.AddRef();
_shared = other._shared;
}
public RefCountable<T> Clone() => new RefCountable<T>(this);
public void Dispose()
{
_shared?.Release();
_shared = null;
}
}
} }

40
src/Skia/Perspex.Skia/StreamGeometryImpl.cs

@ -41,7 +41,11 @@ namespace Perspex.Skia
class StreamGeometryImpl : IStreamGeometryImpl class StreamGeometryImpl : IStreamGeometryImpl
{ {
public SkPath Path; RefCountable<SkPath> _path;
RefCountable<SkPath> _transformedPath;
private Matrix _transform = Matrix.Identity;
public IntPtr EffectivePath => (_transformedPath ?? _path).Handle;
public Rect GetRenderBounds(double strokeThickness) public Rect GetRenderBounds(double strokeThickness)
{ {
@ -51,11 +55,35 @@ namespace Perspex.Skia
public Rect Bounds { get; private set; } public Rect Bounds { get; private set; }
public Matrix Transform { get; set; } = Matrix.Identity; public Matrix Transform
{
get { return _transform; }
set
{
if(_transform == value)
return;
_transform = value;
ApplyTransform();
}
}
void ApplyTransform()
{
if(_path == null)
return;
if (_transformedPath != null)
{
_transformedPath.Dispose();
_transformedPath = null;
}
if (!_transform.IsIdentity)
_transformedPath =
new RefCountable<SkPath>(new SkPath(MethodTable.Instance.TransformPath(_path.Handle, Transform)));
}
public IStreamGeometryImpl Clone() public IStreamGeometryImpl Clone()
{ {
return new StreamGeometryImpl() {Path = Path, Transform = Transform, Bounds = Bounds}; return new StreamGeometryImpl {_path = _path?.Clone(), _transformedPath = _transformedPath?.Clone(), _transform = Transform, Bounds = Bounds};
} }
public IStreamGeometryContextImpl Open() public IStreamGeometryContextImpl Open()
@ -77,7 +105,11 @@ namespace Perspex.Skia
{ {
var arr = _elements.ToArray(); var arr = _elements.ToArray();
SkRect rc; SkRect rc;
_geometryImpl.Path = new SkPath(MethodTable.Instance.CreatePath(arr, arr.Length, out rc)); _geometryImpl._path?.Dispose();
_geometryImpl._path =
new RefCountable<SkPath>(new SkPath(MethodTable.Instance.CreatePath(arr, arr.Length, out rc)));
_geometryImpl.ApplyTransform();
_geometryImpl.Bounds = rc.ToRect(); _geometryImpl.Bounds = rc.ToRect();
} }

12
tests/Perspex.RenderTests/Shapes/PathTests.cs

@ -46,11 +46,7 @@ namespace Perspex.Direct2D1.RenderTests.Shapes
CompareImages(); CompareImages();
} }
#if PERSPEX_SKIA
[Fact(Skip = "FIXME")]
#else
[Fact] [Fact]
#endif
public void Path_Tick_Scaled() public void Path_Tick_Scaled()
{ {
Decorator target = new Decorator Decorator target = new Decorator
@ -73,11 +69,7 @@ namespace Perspex.Direct2D1.RenderTests.Shapes
CompareImages(); CompareImages();
} }
#if PERSPEX_SKIA
[Fact(Skip = "FIXME")]
#else
[Fact] [Fact]
#endif
public void Path_Tick_Scaled_Stroke_8px() public void Path_Tick_Scaled_Stroke_8px()
{ {
Decorator target = new Decorator Decorator target = new Decorator
@ -100,11 +92,7 @@ namespace Perspex.Direct2D1.RenderTests.Shapes
CompareImages(); CompareImages();
} }
#if PERSPEX_SKIA
[Fact(Skip = "FIXME")]
#else
[Fact] [Fact]
#endif
public void Path_Expander_With_Border() public void Path_Expander_With_Border()
{ {
Decorator target = new Decorator Decorator target = new Decorator

Loading…
Cancel
Save