diff --git a/Svg.Tests.Win/SvgClipPathTest.cs b/Svg.Tests.Win/SvgClipPathTest.cs
index 6efa7d358..d1d091cef 100644
--- a/Svg.Tests.Win/SvgClipPathTest.cs
+++ b/Svg.Tests.Win/SvgClipPathTest.cs
@@ -1,10 +1,7 @@
-using System.Diagnostics;
-using System.Linq;
+using System.Linq;
using Shouldly;
using NUnit.Framework;
using SkiaSharp;
-using Svg.Interfaces;
-using Svg.Pathing;
using Svg.Platform;
namespace Svg.Tests.Win;
@@ -82,4 +79,110 @@ public void WhenGettingCliPathBounds_BasedOnClipPathsChildren_GetBounds()
Assert.AreEqual(clip.Bounds.Width, 200);
Assert.AreEqual(clip.Bounds.Height, 50);
}
+
+ [Test]
+ public void WhenGroupClipPathContainsTextTransform_AndTextIsOutsideClip_TextShouldNotBeRendered()
+ {
+ // Arrange
+ const string svg =
+ """
+
+ """;
+
+ // Act
+ using var rendered = RenderSvgFromString(svg, 200, 200);
+
+ // Assert
+ CountNonTransparentPixels(rendered).ShouldBe(0);
+ }
+
+ [Test]
+ public void WhenGroupClipPathContainsTextTransform_AndTextIsInsideClip_TextShouldBeRendered()
+ {
+ // Arrange
+ const string svg =
+ """
+
+ """;
+
+ // Act
+ using var rendered = RenderSvgFromString(svg, 200, 200);
+
+ // Assert
+ CountNonTransparentPixels(rendered).ShouldBeGreaterThan(0);
+ }
+
+ [Test]
+ public void WhenClipPathIsOnGroup_ChildTextTransformShouldNotMoveClipRegion()
+ {
+ // Arrange
+ const string svg =
+ """
+
+ """;
+
+ // Act
+ using var rendered = RenderSvgFromString(svg, 220, 220);
+
+ // Assert
+ CountNonTransparentPixelsInRegion(rendered, 0, 0, 220, 70).ShouldBeGreaterThan(0);
+ CountNonTransparentPixelsInRegion(rendered, 0, 150, 220, 70).ShouldBe(0);
+ }
+
+ private static SKBitmap RenderSvgFromString(string svg, int width, int height)
+ {
+ using SvgDocument doc = SvgDocument.FromSvg(svg);
+ using var surface = SKSurface.Create(new SKImageInfo(width, height));
+ using var renderer = SvgRenderer.FromGraphics(new SkiaGraphics(surface));
+ doc.Draw(renderer);
+ using var image = surface.Snapshot();
+ return SKBitmap.FromImage(image);
+ }
+
+ private static int CountNonTransparentPixels(SKBitmap bitmap)
+ {
+ return CountNonTransparentPixelsInRegion(bitmap, 0, 0, bitmap.Width, bitmap.Height);
+ }
+
+ private static int CountNonTransparentPixelsInRegion(SKBitmap bitmap, int x, int y, int width, int height)
+ {
+ var xStart = x < 0 ? 0 : x;
+ var yStart = y < 0 ? 0 : y;
+ var xEnd = x + width > bitmap.Width ? bitmap.Width : x + width;
+ var yEnd = y + height > bitmap.Height ? bitmap.Height : y + height;
+
+ var count = 0;
+ for (var yy = yStart; yy < yEnd; yy++)
+ {
+ for (var xx = xStart; xx < xEnd; xx++)
+ {
+ if (bitmap.GetPixel(xx, yy).Alpha > 0)
+ {
+ count++;
+ }
+ }
+ }
+
+ return count;
+ }
}
\ No newline at end of file
diff --git a/Svg/Basic Shapes/SvgVisualElement.cs b/Svg/Basic Shapes/SvgVisualElement.cs
index a9fa45066..d5caf20c9 100644
--- a/Svg/Basic Shapes/SvgVisualElement.cs
+++ b/Svg/Basic Shapes/SvgVisualElement.cs
@@ -150,10 +150,10 @@ protected internal virtual bool IntersectsWith(RectangleF rectangle, Matrix tran
return true;
}
- private SvgAttributeCollection.InheritedAttribute _clip;
- private SvgAttributeCollection.InheritedAttribute _clipPath;
- private SvgAttributeCollection.InheritedAttribute _filter;
- private SvgAttributeCollection.Attribute _clipRule;
+ private SvgAttributeCollection.Attribute _clip;
+ private SvgAttributeCollection.Attribute _clipPath;
+ private SvgAttributeCollection.Attribute _filter;
+ private SvgAttributeCollection.InheritedAttribute _clipRule;
///
/// Gets the associated if one has been specified.
@@ -161,7 +161,7 @@ protected internal virtual bool IntersectsWith(RectangleF rectangle, Matrix tran
[SvgAttribute("clip")]
public virtual string Clip
{
- get { return (_clip ??= this.Attributes.GetInheritedAttribute("clip")).GetValue(); }
+ get { return (_clip ??= this.Attributes.GetAttribute("clip")).GetValue(); }
set { this.Attributes["clip"] = value; }
}
@@ -171,7 +171,7 @@ public virtual string Clip
[SvgAttribute("clip-path")]
public virtual Uri ClipPath
{
- get { return (_clipPath ??= this.Attributes.GetInheritedAttribute("clip-path")).GetValue(); }
+ get { return (_clipPath ??= this.Attributes.GetAttribute("clip-path")).GetValue(); }
set { this.Attributes["clip-path"] = value; }
}
@@ -181,7 +181,7 @@ public virtual Uri ClipPath
[SvgAttribute("clip-rule")]
public SvgClipRule ClipRule
{
- get { return (_clipRule ??= this.Attributes.GetAttribute("clip-rule", SvgClipRule.NonZero)).GetValue(); }
+ get { return (_clipRule ??= this.Attributes.GetInheritedAttribute("clip-rule")).GetValue(); }
set { this.Attributes["clip-rule"] = value; }
}
@@ -191,7 +191,7 @@ public SvgClipRule ClipRule
[SvgAttribute("filter")]
public virtual Uri Filter
{
- get { return (_filter ??= this.Attributes.GetInheritedAttribute("filter")).GetValue(); }
+ get { return (_filter ??= this.Attributes.GetAttribute("filter")).GetValue(); }
set { this.Attributes["filter"] = value; }
}
@@ -278,7 +278,9 @@ private void Render(ISvgRenderer renderer, bool renderFilter, RenderCacheEntry c
}
else
{
+ this.SetClip(renderer);
base.RenderChildren(renderer);
+ this.ResetClip(renderer);
}
this.PopTransforms(renderer);
}
diff --git a/Svg/Converters/BaseConverter.cs b/Svg/Converters/BaseConverter.cs
index 4bbae5022..5cdbb13d7 100644
--- a/Svg/Converters/BaseConverter.cs
+++ b/Svg/Converters/BaseConverter.cs
@@ -235,6 +235,9 @@ public SvgFontVariantConverter() : base(SvgFontVariant.Normal) { }
public override object ConvertFromString(string value, Type targetType, SvgDocument document)
{
+ if (value == "none")
+ return SvgFontVariant.Normal;
+
if (value == "small-caps")
return SvgFontVariant.Smallcaps;
diff --git a/Svg/Svg.csproj b/Svg/Svg.csproj
index 7b02f8710..0c486a62d 100644
--- a/Svg/Svg.csproj
+++ b/Svg/Svg.csproj
@@ -3,10 +3,12 @@
netstandard2.0;net48;net9.0
PackageReference
- 3.1.2-optiq06
+ 3.1.2-optiq07
gentledpp,zepr
Opti-Q GmbH
+ #3.1.2-optiq07
+ Fixed clip path property being inherited
#3.1.2-optiq06
Fixed: Sketch, when setting text and cancel dialog, opens new dialog and asks for font size
#3.1.2-optiq05