diff --git a/src/Skia/Avalonia.Skia/GeometryImpl.cs b/src/Skia/Avalonia.Skia/GeometryImpl.cs
index 0884399f4e..5042e6ebd2 100644
--- a/src/Skia/Avalonia.Skia/GeometryImpl.cs
+++ b/src/Skia/Avalonia.Skia/GeometryImpl.cs
@@ -11,12 +11,27 @@ namespace Avalonia.Skia
internal abstract class GeometryImpl : IGeometryImpl
{
private PathCache _pathCache;
-
+ private SKPathMeasure _pathMeasureCache;
+
///
public abstract Rect Bounds { get; }
-
+
///
- public double ContourLength => _pathCache.CachePathMeasure?.Length ?? 0;
+ public double ContourLength
+ {
+ get
+ {
+ if (EffectivePath is null)
+ return 0;
+
+ if (_pathMeasureCache is null)
+ {
+ _pathMeasureCache = new SKPathMeasure(EffectivePath);
+ }
+
+ return (double)_pathMeasureCache?.Length;
+ }
+ }
public abstract SKPath EffectivePath { get; }
@@ -34,12 +49,12 @@ namespace Avalonia.Skia
// Usually this function is being called with same stroke width per path, so this saves a lot of Skia traffic.
var strokeWidth = (float)(pen?.Thickness ?? 0);
-
+
if (!_pathCache.HasCacheFor(strokeWidth))
{
UpdatePathCache(strokeWidth);
}
-
+
return PathContainsCore(_pathCache.CachedStrokePath, point);
}
@@ -62,7 +77,7 @@ namespace Avalonia.Skia
{
paint.IsStroke = true;
paint.StrokeWidth = strokeWidth;
-
+
paint.GetFillPath(EffectivePath, strokePath);
_pathCache.Cache(strokePath, strokeWidth, strokePath.TightBounds.ToAvaloniaRect());
@@ -78,13 +93,13 @@ namespace Avalonia.Skia
/// True, if point is contained in a path.
private static bool PathContainsCore(SKPath path, Point point)
{
- return path.Contains((float)point.X, (float)point.Y);
+ return path.Contains((float)point.X, (float)point.Y);
}
///
public IGeometryImpl Intersect(IGeometryImpl geometry)
{
- var result = EffectivePath.Op(((GeometryImpl) geometry).EffectivePath, SKPathOp.Intersect);
+ var result = EffectivePath.Op(((GeometryImpl)geometry).EffectivePath, SKPathOp.Intersect);
return result == null ? null : new StreamGeometryImpl(result);
}
@@ -93,70 +108,86 @@ namespace Avalonia.Skia
public Rect GetRenderBounds(IPen pen)
{
var strokeWidth = (float)(pen?.Thickness ?? 0);
-
+
if (!_pathCache.HasCacheFor(strokeWidth))
{
UpdatePathCache(strokeWidth);
}
-
+
return _pathCache.CachedGeometryRenderBounds;
}
-
+
///
public ITransformedGeometryImpl WithTransform(Matrix transform)
{
return new TransformedGeometryImpl(this, transform);
}
-
+
///
public bool TryGetPointAtDistance(double distance, out Point point)
{
- if (_pathCache.CachePathMeasure is null)
+ if (EffectivePath is null)
{
point = new Point();
return false;
}
-
- var res = _pathCache.CachePathMeasure.GetPosition((float)distance, out var skPoint);
+
+ if (_pathMeasureCache is null)
+ {
+ _pathMeasureCache = new SKPathMeasure(EffectivePath);
+ }
+
+ var res = _pathMeasureCache.GetPosition((float)distance, out var skPoint);
point = new Point(skPoint.X, skPoint.Y);
return res;
}
-
+
///
public bool TryGetPointAndTangentAtDistance(double distance, out Point point, out Point tangent)
{
- if (_pathCache.CachePathMeasure is null)
+ if (EffectivePath is null)
{
point = new Point();
tangent = new Point();
return false;
}
-
- var res = _pathCache.CachePathMeasure.GetPositionAndTangent((float)distance, out var skPoint, out var skTangent);
+
+ if (_pathMeasureCache is null)
+ {
+ _pathMeasureCache = new SKPathMeasure(EffectivePath);
+ }
+
+ var res = _pathMeasureCache.GetPositionAndTangent((float)distance, out var skPoint, out var skTangent);
point = new Point(skPoint.X, skPoint.Y);
tangent = new Point(skTangent.X, skTangent.Y);
return res;
}
- public bool TryGetSegment(float startDistance, float stopDistance, bool startOnBeginFigure, out IGeometryImpl segmentGeometry)
+ public bool TryGetSegment(float startDistance, float stopDistance, bool startOnBeginFigure,
+ out IGeometryImpl segmentGeometry)
{
- if (_pathCache.CachePathMeasure is null)
+ if (EffectivePath is null)
{
segmentGeometry = null;
return false;
}
+
+ if (_pathMeasureCache is null)
+ {
+ _pathMeasureCache = new SKPathMeasure(EffectivePath);
+ }
segmentGeometry = null;
SKPath _skPathSegment = null;
- var res = _pathCache.CachePathMeasure.GetSegment(startDistance, stopDistance, _skPathSegment, startOnBeginFigure);
+ var res = _pathMeasureCache.GetSegment(startDistance, stopDistance, _skPathSegment, startOnBeginFigure);
if (res)
{
segmentGeometry = new StreamGeometryImpl(_skPathSegment);
}
-
+
return res;
}
@@ -176,7 +207,7 @@ namespace Avalonia.Skia
/// Tolerance for two stroke widths to be deemed equal
///
public const float Tolerance = float.Epsilon;
-
+
///
/// Cached contour path.
///
@@ -186,11 +217,6 @@ namespace Avalonia.Skia
/// Cached geometry render bounds.
///
public Rect CachedGeometryRenderBounds { get; private set; }
-
- ///
- /// Cached path measurement helper.
- ///
- public SKPathMeasure CachePathMeasure { get; private set; }
///
/// Is cached valid for given stroke width.
@@ -216,8 +242,7 @@ namespace Avalonia.Skia
}
CachedStrokePath = path;
- CachedGeometryRenderBounds = geometryRenderBounds;
- CachePathMeasure = new SKPathMeasure(path);
+ CachedGeometryRenderBounds = geometryRenderBounds;
_cachedStrokeWidth = strokeWidth;
}
@@ -227,7 +252,6 @@ namespace Avalonia.Skia
public void Invalidate()
{
CachedStrokePath?.Dispose();
- CachePathMeasure?.Dispose();
CachedGeometryRenderBounds = Rect.Empty;
_cachedStrokeWidth = default(float);
}