diff --git a/samples/svgc/ImageSharpAssetLoader.cs b/samples/svgc/ImageSharpAssetLoader.cs
index 598eab9aa0..746a335bcc 100644
--- a/samples/svgc/ImageSharpAssetLoader.cs
+++ b/samples/svgc/ImageSharpAssetLoader.cs
@@ -56,4 +56,9 @@ public float MeasureText(string? text, ShimSkiaSharp.SKPaint paint, ref ShimSkia
bounds = new ShimSkiaSharp.SKRect(0, -size * 0.8f, width, size * 0.2f);
return width;
}
+
+ public ShimSkiaSharp.SKPath? GetTextPath(string? text, ShimSkiaSharp.SKPaint paint, float x, float y)
+ {
+ return null;
+ }
}
diff --git a/src/Svg.Controls.Avalonia/AvaloniaSvgAssetLoader.cs b/src/Svg.Controls.Avalonia/AvaloniaSvgAssetLoader.cs
index 9fac52c405..a3f67796f8 100644
--- a/src/Svg.Controls.Avalonia/AvaloniaSvgAssetLoader.cs
+++ b/src/Svg.Controls.Avalonia/AvaloniaSvgAssetLoader.cs
@@ -173,4 +173,10 @@ public float MeasureText(string? text, SKPaint paint, ref SKRect bounds)
bounds = new SKRect(0, -ascent, width, descent);
return width;
}
+
+ ///
+ public SKPath? GetTextPath(string? text, SKPaint paint, float x, float y)
+ {
+ return null;
+ }
}
diff --git a/src/Svg.Model/Drawables/Elements/TextDrawable.cs b/src/Svg.Model/Drawables/Elements/TextDrawable.cs
index c98ecf7b02..fa20c3b914 100644
--- a/src/Svg.Model/Drawables/Elements/TextDrawable.cs
+++ b/src/Svg.Model/Drawables/Elements/TextDrawable.cs
@@ -18,6 +18,8 @@ public sealed class TextDrawable : DrawableBase
public SKRect OwnerBounds { get; set; }
+ public SKPath? Path { get; private set; }
+
private TextDrawable(ISvgAssetLoader assetLoader, HashSet? references)
: base(assetLoader, references)
{
@@ -87,6 +89,7 @@ private void Initialize()
var width = AssetLoader.MeasureText(text, paint, ref bounds);
GeometryBounds = new SKRect(x, y + metricsAscent, x + width, y + metricsDescent);
+ Path = AssetLoader.GetTextPath(text, paint, x, y);
Transform = TransformsService.ToMatrix(Text.Transforms);
}
diff --git a/src/Svg.Model/ISvgAssetLoader.cs b/src/Svg.Model/ISvgAssetLoader.cs
index ddbd41be7c..e57634279a 100644
--- a/src/Svg.Model/ISvgAssetLoader.cs
+++ b/src/Svg.Model/ISvgAssetLoader.cs
@@ -14,4 +14,5 @@ public interface ISvgAssetLoader
List FindTypefaces(string? text, SKPaint paintPreferredTypeface);
SKFontMetrics GetFontMetrics(SKPaint paint);
float MeasureText(string? text, SKPaint paint, ref SKRect bounds);
+ SKPath? GetTextPath(string? text, SKPaint paint, float x, float y);
}
diff --git a/src/Svg.Skia/SkiaModel.cs b/src/Svg.Skia/SkiaModel.cs
index 906b40e8ae..bb1c704ef5 100644
--- a/src/Svg.Skia/SkiaModel.cs
+++ b/src/Svg.Skia/SkiaModel.cs
@@ -994,6 +994,15 @@ public SkiaSharp.SKPathFillType ToSKPathFillType(SKPathFillType pathFillType)
};
}
+ public SKPathFillType FromSKPathFillType(SkiaSharp.SKPathFillType pathFillType)
+ {
+ return pathFillType switch
+ {
+ SkiaSharp.SKPathFillType.EvenOdd => SKPathFillType.EvenOdd,
+ _ => SKPathFillType.Winding
+ };
+ }
+
public SkiaSharp.SKPathArcSize ToSKPathArcSize(SKPathArcSize pathArcSize)
{
return pathArcSize switch
@@ -1130,6 +1139,42 @@ public SkiaSharp.SKPath ToSKPath(SKPath path)
return skPath;
}
+ public SKPath FromSKPath(SkiaSharp.SKPath skPath)
+ {
+ var path = new SKPath
+ {
+ FillType = FromSKPathFillType(skPath.FillType)
+ };
+
+ using var iter = skPath.CreateRawIterator();
+ var pts = new SkiaSharp.SKPoint[4];
+ while (true)
+ {
+ var verb = iter.Next(pts);
+ switch (verb)
+ {
+ case SkiaSharp.SKPathVerb.Move:
+ path.Commands?.Add(new MoveToPathCommand(pts[0].X, pts[0].Y));
+ break;
+ case SkiaSharp.SKPathVerb.Line:
+ path.Commands?.Add(new LineToPathCommand(pts[1].X, pts[1].Y));
+ break;
+ case SkiaSharp.SKPathVerb.Quad:
+ case SkiaSharp.SKPathVerb.Conic:
+ path.Commands?.Add(new QuadToPathCommand(pts[1].X, pts[1].Y, pts[2].X, pts[2].Y));
+ break;
+ case SkiaSharp.SKPathVerb.Cubic:
+ path.Commands?.Add(new CubicToPathCommand(pts[1].X, pts[1].Y, pts[2].X, pts[2].Y, pts[3].X, pts[3].Y));
+ break;
+ case SkiaSharp.SKPathVerb.Close:
+ path.Commands?.Add(new ClosePathCommand());
+ break;
+ case SkiaSharp.SKPathVerb.Done:
+ return path;
+ }
+ }
+ }
+
public SkiaSharp.SKPath? ToSKPath(ClipPath? clipPath)
{
if (clipPath?.Clips is null)
diff --git a/src/Svg.Skia/SkiaSvgAssetLoader.cs b/src/Svg.Skia/SkiaSvgAssetLoader.cs
index 5ecc33e95d..abbe8a646f 100644
--- a/src/Svg.Skia/SkiaSvgAssetLoader.cs
+++ b/src/Svg.Skia/SkiaSvgAssetLoader.cs
@@ -151,4 +151,17 @@ public float MeasureText(string? text, ShimSkiaSharp.SKPaint paint, ref ShimSkia
bounds = new ShimSkiaSharp.SKRect(skBounds.Left, skBounds.Top, skBounds.Right, skBounds.Bottom);
return width;
}
+
+ ///
+ public ShimSkiaSharp.SKPath? GetTextPath(string? text, ShimSkiaSharp.SKPaint paint, float x, float y)
+ {
+ using var skPaint = _skiaModel.ToSKPaint(paint);
+ if (skPaint is null || text is null)
+ {
+ return null;
+ }
+
+ using var skPath = skPaint.GetTextPath(text, x, y);
+ return _skiaModel.FromSKPath(skPath);
+ }
}
diff --git a/src/Svg.SourceGenerator.Skia/SkiaGeneratorSvgAssetLoader.cs b/src/Svg.SourceGenerator.Skia/SkiaGeneratorSvgAssetLoader.cs
index 7f971a0d3d..5f1725df71 100644
--- a/src/Svg.SourceGenerator.Skia/SkiaGeneratorSvgAssetLoader.cs
+++ b/src/Svg.SourceGenerator.Skia/SkiaGeneratorSvgAssetLoader.cs
@@ -57,4 +57,9 @@ public float MeasureText(string? text, ShimSkiaSharp.SKPaint paint, ref ShimSkia
bounds = new ShimSkiaSharp.SKRect(0, -size * 0.8f, width, size * 0.2f);
return width;
}
+
+ public ShimSkiaSharp.SKPath? GetTextPath(string? text, ShimSkiaSharp.SKPaint paint, float x, float y)
+ {
+ return null;
+ }
}