diff --git a/itext.tests/itext.svg.tests/itext/svg/renderers/OpacityTest.cs b/itext.tests/itext.svg.tests/itext/svg/renderers/OpacityTest.cs
index a3c9f6c51..dac31926f 100644
--- a/itext.tests/itext.svg.tests/itext/svg/renderers/OpacityTest.cs
+++ b/itext.tests/itext.svg.tests/itext/svg/renderers/OpacityTest.cs
@@ -60,9 +60,7 @@ public virtual void TestRGBA() {
[NUnit.Framework.Test]
public virtual void TestFillOpacityWithComma() {
- //TODO DEVSIX-2678 SVG: Displaying invalid value of fill-opacity incorrectly
- NUnit.Framework.Assert.Catch(typeof(FormatException), () => ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER
- , "testFillOpacityWithComma"));
+ ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "testFillOpacityWithComma");
}
[NUnit.Framework.Test]
@@ -72,15 +70,12 @@ public virtual void TestFillOpacityWithPercents() {
[NUnit.Framework.Test]
public virtual void TestFillOpacity() {
- //TODO: update after DEVSIX-2678 fix
ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "svg_fill_opacity");
}
[NUnit.Framework.Test]
public virtual void TestStrokeOpacityWithComma() {
- //TODO DEVSIX-2679
- NUnit.Framework.Assert.Catch(typeof(Exception), () => ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER,
- "testStrokeOpacityWithComma"));
+ ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "testStrokeOpacityWithComma");
}
[NUnit.Framework.Test]
@@ -90,7 +85,6 @@ public virtual void TestStrokeOpacityWithPercents() {
[NUnit.Framework.Test]
public virtual void TestStrokeOpacity() {
- //TODO: update after DEVSIX-2679 fix
ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "svg_stroke_opacity");
}
}
diff --git a/itext.tests/itext.svg.tests/itext/svg/renderers/VectorEffectTest.cs b/itext.tests/itext.svg.tests/itext/svg/renderers/VectorEffectTest.cs
new file mode 100644
index 000000000..398e32f18
--- /dev/null
+++ b/itext.tests/itext.svg.tests/itext/svg/renderers/VectorEffectTest.cs
@@ -0,0 +1,108 @@
+/*
+This file is part of the iText (R) project.
+Copyright (c) 1998-2025 Apryse Group NV
+Authors: Apryse Software.
+
+This program is offered under a commercial and under the AGPL license.
+For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
+
+AGPL licensing:
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+*/
+using System;
+using iText.Svg.Logs;
+using iText.Test;
+using iText.Test.Attributes;
+
+namespace iText.Svg.Renderers {
+ [NUnit.Framework.Category("IntegrationTest")]
+ public class VectorEffectTest : SvgIntegrationTest {
+ private static readonly String SOURCE_FOLDER = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext
+ .CurrentContext.TestDirectory) + "/resources/itext/svg/renderers/VectorEffectTest/";
+
+ private static readonly String DESTINATION_FOLDER = NUnit.Framework.TestContext.CurrentContext.TestDirectory
+ + "/test/itext/svg/renderers/VectorEffectTest/";
+
+ [NUnit.Framework.OneTimeSetUp]
+ public static void BeforeClass() {
+ ITextTest.CreateDestinationFolder(DESTINATION_FOLDER);
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void NonScalingStrokeTest() {
+ ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "nonScalingStroke");
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void NonScalingStrokePathTest() {
+ ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "nonScalingStrokePath");
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void NonScalingStrokeFiguresTest() {
+ ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "nonScalingStrokeFigures");
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void NonScalingStrokeTextTest() {
+ // TODO DEVSIX-8850 support vector-effect for text and tspan
+ ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "nonScalingStrokeText");
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void PreserveAspectRatioTest() {
+ ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "preserveAspectRatio");
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void SvgWithSvgTest() {
+ ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "svgWithSvg");
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void SeveralTransformationsTest() {
+ // TODO DEVSIX-8850 support vector-effect for text and tspan
+ ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "severalTransformations");
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void SeveralNestedSvgTest() {
+ ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "severalNestedSvg");
+ }
+
+ [NUnit.Framework.Test]
+ [LogMessage(iText.StyledXmlParser.Logs.StyledXmlParserLogMessageConstant.UNABLE_TO_RETRIEVE_IMAGE_WITH_GIVEN_BASE_URI
+ )]
+ public virtual void ImageWithSvgTest() {
+ // TODO DEVSIX-8884 Support svg format for image href attribute
+ ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "imageWithSvg");
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void ClipPathTest() {
+ ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "clipPath");
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void VectorEffectOnUseTest() {
+ ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "vectorEffectOnUse");
+ }
+
+ [NUnit.Framework.Test]
+ [LogMessage(SvgLogMessageConstant.NON_INVERTIBLE_TRANSFORMATION_MATRIX_FOR_NON_SCALING_STROKE)]
+ public virtual void NonInvertibleMatrixTest() {
+ ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "nonInvertibleMatrix");
+ }
+ }
+}
diff --git a/itext.tests/itext.svg.tests/itext/svg/renderers/impl/ClipPathSvgNodeRendererIntegrationTest.cs b/itext.tests/itext.svg.tests/itext/svg/renderers/impl/ClipPathSvgNodeRendererIntegrationTest.cs
index 81f4943b6..3f34b642d 100644
--- a/itext.tests/itext.svg.tests/itext/svg/renderers/impl/ClipPathSvgNodeRendererIntegrationTest.cs
+++ b/itext.tests/itext.svg.tests/itext/svg/renderers/impl/ClipPathSvgNodeRendererIntegrationTest.cs
@@ -42,6 +42,16 @@ public static void BeforeClass() {
ITextTest.CreateDestinationFolder(DESTINATION_FOLDER);
}
+ [NUnit.Framework.Test]
+ public virtual void EmptyClipPathTest() {
+ ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "emptyClipPath");
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void InvalidClipPathTest() {
+ ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "invalidClipPath");
+ }
+
[NUnit.Framework.Test]
public virtual void RectClipPathComplexTest() {
ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "clippath_rect_complex");
diff --git a/itext.tests/itext.svg.tests/itext/svg/renderers/impl/ImageSvgNodeRendererIntegrationTest.cs b/itext.tests/itext.svg.tests/itext/svg/renderers/impl/ImageSvgNodeRendererIntegrationTest.cs
index 2e91ec564..4d8b3089f 100644
--- a/itext.tests/itext.svg.tests/itext/svg/renderers/impl/ImageSvgNodeRendererIntegrationTest.cs
+++ b/itext.tests/itext.svg.tests/itext/svg/renderers/impl/ImageSvgNodeRendererIntegrationTest.cs
@@ -54,6 +54,11 @@ public virtual void SingleImageTest() {
ConvertAndCompareSinglePage(sourceFolder, destinationFolder, "singleImage", properties);
}
+ [NUnit.Framework.Test]
+ public virtual void SingleImageHrefTest() {
+ ConvertAndCompareSinglePage(sourceFolder, destinationFolder, "singleImageHref", properties);
+ }
+
[NUnit.Framework.Test]
public virtual void ImageWithRectangleTest() {
ConvertAndCompareSinglePage(sourceFolder, destinationFolder, "imageWithRectangle", properties);
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/JFreeSvgTest/cmp_usingJFreeSvgBarChartFromFileTest.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/JFreeSvgTest/cmp_usingJFreeSvgBarChartFromFileTest.pdf
index 8b4070709..5c2b05618 100644
Binary files a/itext.tests/itext.svg.tests/resources/itext/svg/JFreeSvgTest/cmp_usingJFreeSvgBarChartFromFileTest.pdf and b/itext.tests/itext.svg.tests/resources/itext/svg/JFreeSvgTest/cmp_usingJFreeSvgBarChartFromFileTest.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/JFreeSvgTest/cmp_usingJFreeSvgBarChartFromStringTest.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/JFreeSvgTest/cmp_usingJFreeSvgBarChartFromStringTest.pdf
index 5d59de601..9f432631e 100644
Binary files a/itext.tests/itext.svg.tests/resources/itext/svg/JFreeSvgTest/cmp_usingJFreeSvgBarChartFromStringTest.pdf and b/itext.tests/itext.svg.tests/resources/itext/svg/JFreeSvgTest/cmp_usingJFreeSvgBarChartFromStringTest.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/JFreeSvgTest/cmp_usingJFreeSvgPieChartFromFileTest.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/JFreeSvgTest/cmp_usingJFreeSvgPieChartFromFileTest.pdf
index f0670160d..df2fd47e7 100644
Binary files a/itext.tests/itext.svg.tests/resources/itext/svg/JFreeSvgTest/cmp_usingJFreeSvgPieChartFromFileTest.pdf and b/itext.tests/itext.svg.tests/resources/itext/svg/JFreeSvgTest/cmp_usingJFreeSvgPieChartFromFileTest.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/SvgStyleResolver/cmp_chartWithText1.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/css/SvgStyleResolver/cmp_chartWithText1.pdf
index be6e4dc53..bd29fbb72 100644
Binary files a/itext.tests/itext.svg.tests/resources/itext/svg/css/SvgStyleResolver/cmp_chartWithText1.pdf and b/itext.tests/itext.svg.tests/resources/itext/svg/css/SvgStyleResolver/cmp_chartWithText1.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/googlecharts/IntervalsChartsTest/cmp_intervalsBackgroundBoxChart.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/googlecharts/IntervalsChartsTest/cmp_intervalsBackgroundBoxChart.pdf
index 3d770f15b..bb5c01b54 100644
Binary files a/itext.tests/itext.svg.tests/resources/itext/svg/googlecharts/IntervalsChartsTest/cmp_intervalsBackgroundBoxChart.pdf and b/itext.tests/itext.svg.tests/resources/itext/svg/googlecharts/IntervalsChartsTest/cmp_intervalsBackgroundBoxChart.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/googlecharts/SteppedAreaChartsTest/cmp_steppedArea2Chart.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/googlecharts/SteppedAreaChartsTest/cmp_steppedArea2Chart.pdf
index 28881216f..aab8b7028 100644
Binary files a/itext.tests/itext.svg.tests/resources/itext/svg/googlecharts/SteppedAreaChartsTest/cmp_steppedArea2Chart.pdf and b/itext.tests/itext.svg.tests/resources/itext/svg/googlecharts/SteppedAreaChartsTest/cmp_steppedArea2Chart.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/googlecharts/SteppedAreaChartsTest/cmp_steppedAreaChart.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/googlecharts/SteppedAreaChartsTest/cmp_steppedAreaChart.pdf
index fa6866cf4..bda9755a9 100644
Binary files a/itext.tests/itext.svg.tests/resources/itext/svg/googlecharts/SteppedAreaChartsTest/cmp_steppedAreaChart.pdf and b/itext.tests/itext.svg.tests/resources/itext/svg/googlecharts/SteppedAreaChartsTest/cmp_steppedAreaChart.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/clipPath.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/clipPath.svg
new file mode 100644
index 000000000..463888da4
--- /dev/null
+++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/clipPath.svg
@@ -0,0 +1,53 @@
+
+
\ No newline at end of file
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_clipPath.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_clipPath.pdf
new file mode 100644
index 000000000..6a07662c2
Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_clipPath.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_imageWithSvg.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_imageWithSvg.pdf
new file mode 100644
index 000000000..e29a48913
Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_imageWithSvg.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_nonInvertibleMatrix.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_nonInvertibleMatrix.pdf
new file mode 100644
index 000000000..845ec4bfc
Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_nonInvertibleMatrix.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_nonScalingStroke.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_nonScalingStroke.pdf
new file mode 100644
index 000000000..930ac93c9
Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_nonScalingStroke.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_nonScalingStrokeFigures.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_nonScalingStrokeFigures.pdf
new file mode 100644
index 000000000..9d419c8ef
Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_nonScalingStrokeFigures.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_nonScalingStrokePath.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_nonScalingStrokePath.pdf
new file mode 100644
index 000000000..dcd10285d
Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_nonScalingStrokePath.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_nonScalingStrokeText.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_nonScalingStrokeText.pdf
new file mode 100644
index 000000000..899891c2b
Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_nonScalingStrokeText.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_preserveAspectRatio.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_preserveAspectRatio.pdf
new file mode 100644
index 000000000..cd7c15d20
Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_preserveAspectRatio.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_severalNestedSvg.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_severalNestedSvg.pdf
new file mode 100644
index 000000000..2b68a6f8e
Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_severalNestedSvg.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_severalTransformations.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_severalTransformations.pdf
new file mode 100644
index 000000000..67830cbef
Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_severalTransformations.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_svgWithSvg.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_svgWithSvg.pdf
new file mode 100644
index 000000000..2a11d1368
Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_svgWithSvg.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_vectorEffectOnUse.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_vectorEffectOnUse.pdf
new file mode 100644
index 000000000..3b975c102
Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/cmp_vectorEffectOnUse.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/image.png b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/image.png
new file mode 100644
index 000000000..2ffed0aff
Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/image.png differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/imageWithSvg.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/imageWithSvg.svg
new file mode 100644
index 000000000..6330efb8b
--- /dev/null
+++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/imageWithSvg.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/nonInvertibleMatrix.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/nonInvertibleMatrix.svg
new file mode 100644
index 000000000..f2757b08d
--- /dev/null
+++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/nonInvertibleMatrix.svg
@@ -0,0 +1,15 @@
+
+
\ No newline at end of file
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/nonScalingStroke.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/nonScalingStroke.svg
new file mode 100644
index 000000000..e19689236
--- /dev/null
+++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/nonScalingStroke.svg
@@ -0,0 +1,11 @@
+
+
\ No newline at end of file
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/nonScalingStrokeFigures.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/nonScalingStrokeFigures.svg
new file mode 100644
index 000000000..9aed284f9
--- /dev/null
+++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/nonScalingStrokeFigures.svg
@@ -0,0 +1,60 @@
+
+
+
+
+
+ use
+
+
+
+ Example non-scaling stroke
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text
+ text
+
+
+ tspan
+
+ tspan
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/nonScalingStrokePath.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/nonScalingStrokePath.svg
new file mode 100644
index 000000000..2360d9051
--- /dev/null
+++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/nonScalingStrokePath.svg
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/nonScalingStrokeText.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/nonScalingStrokeText.svg
new file mode 100644
index 000000000..025009735
--- /dev/null
+++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/nonScalingStrokeText.svg
@@ -0,0 +1,48 @@
+
+
+ Example non-scaling stroke in text and tspan
+
+
+
+
+ 1
+ 2
+
+ 2+ve
+
+ 3
+
+ 4
+
+
+ 4+ve
+
+
+
+ 3+ve
+
+
+
+
+ 1+ve
+ 2
+
+ 2+ve
+
+ 3
+
+ 4
+
+
+ 4+ve
+
+
+
+ 3+ve
+
+
+
+
+
+
\ No newline at end of file
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/preserveAspectRatio.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/preserveAspectRatio.svg
new file mode 100644
index 000000000..60dc4acc3
--- /dev/null
+++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/preserveAspectRatio.svg
@@ -0,0 +1,61 @@
+
+
+
+
+
+ use
+
+
+
+ Example non-scaling stroke
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text
+ text
+
+
+ tspan
+
+ tspan
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/severalNestedSvg.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/severalNestedSvg.svg
new file mode 100644
index 000000000..6017468e1
--- /dev/null
+++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/severalNestedSvg.svg
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A
+ A
+
+
+
+ B
+
+ B
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/severalTransformations.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/severalTransformations.svg
new file mode 100644
index 000000000..65e1a6586
--- /dev/null
+++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/severalTransformations.svg
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A
+
+ B
+
+ C
+
+
+ A
+
+ B
+
+ C
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/svgWithSvg.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/svgWithSvg.svg
new file mode 100644
index 000000000..cc5e5b15b
--- /dev/null
+++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/svgWithSvg.svg
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A
+ A
+
+
+ B
+
+ B
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/vectorEffectOnUse.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/vectorEffectOnUse.svg
new file mode 100644
index 000000000..da4f9f7ac
--- /dev/null
+++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/VectorEffectTest/vectorEffectOnUse.svg
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/ClipPathTest/cmp_emptyClipPath.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/ClipPathTest/cmp_emptyClipPath.pdf
new file mode 100644
index 000000000..9aba1573d
Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/ClipPathTest/cmp_emptyClipPath.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/ClipPathTest/cmp_invalidClipPath.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/ClipPathTest/cmp_invalidClipPath.pdf
new file mode 100644
index 000000000..4db4a82f6
Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/ClipPathTest/cmp_invalidClipPath.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/ClipPathTest/emptyClipPath.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/ClipPathTest/emptyClipPath.svg
new file mode 100644
index 000000000..ae1e5341a
--- /dev/null
+++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/ClipPathTest/emptyClipPath.svg
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+ text
+
\ No newline at end of file
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/ClipPathTest/invalidClipPath.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/ClipPathTest/invalidClipPath.svg
new file mode 100644
index 000000000..84f3529e4
--- /dev/null
+++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/ClipPathTest/invalidClipPath.svg
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+ text
+
\ No newline at end of file
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/ImageSvgNodeRendererTest/cmp_singleImageHref.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/ImageSvgNodeRendererTest/cmp_singleImageHref.pdf
new file mode 100644
index 000000000..f0c879e2f
Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/ImageSvgNodeRendererTest/cmp_singleImageHref.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/ImageSvgNodeRendererTest/singleImageHref.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/ImageSvgNodeRendererTest/singleImageHref.svg
new file mode 100644
index 000000000..36235cdfc
--- /dev/null
+++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/ImageSvgNodeRendererTest/singleImageHref.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/OpacityTest/cmp_testFillOpacityWithComma.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/OpacityTest/cmp_testFillOpacityWithComma.pdf
new file mode 100644
index 000000000..3071c72ef
Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/OpacityTest/cmp_testFillOpacityWithComma.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/OpacityTest/cmp_testStrokeOpacityWithComma.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/OpacityTest/cmp_testStrokeOpacityWithComma.pdf
new file mode 100644
index 000000000..656d9cea0
Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/OpacityTest/cmp_testStrokeOpacityWithComma.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/OpacityTest/testStrokeOpacityWithComma.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/OpacityTest/testStrokeOpacityWithComma.svg
new file mode 100644
index 000000000..04f0346bb
--- /dev/null
+++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/OpacityTest/testStrokeOpacityWithComma.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/OpacityTest/testStrokeOpacityWithPercents.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/OpacityTest/testStrokeOpacityWithPercents.svg
index 18752fbe2..240b1e244 100644
--- a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/OpacityTest/testStrokeOpacityWithPercents.svg
+++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/OpacityTest/testStrokeOpacityWithPercents.svg
@@ -1,12 +1,12 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/RectangleSvgNodeRendererTest/cmp_basicCircularRoundedRxRectangle.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/RectangleSvgNodeRendererTest/cmp_basicCircularRoundedRxRectangle.pdf
index ebf0ed0c3..6c125da21 100644
Binary files a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/RectangleSvgNodeRendererTest/cmp_basicCircularRoundedRxRectangle.pdf and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/RectangleSvgNodeRendererTest/cmp_basicCircularRoundedRxRectangle.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/RectangleSvgNodeRendererTest/cmp_basicCircularRoundedRyRectangle.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/RectangleSvgNodeRendererTest/cmp_basicCircularRoundedRyRectangle.pdf
index cb6f3ec96..f5c6c9eed 100644
Binary files a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/RectangleSvgNodeRendererTest/cmp_basicCircularRoundedRyRectangle.pdf and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/RectangleSvgNodeRendererTest/cmp_basicCircularRoundedRyRectangle.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/RectangleSvgNodeRendererTest/cmp_basicEllipticalNegativeHeightRoundedRectangle.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/RectangleSvgNodeRendererTest/cmp_basicEllipticalNegativeHeightRoundedRectangle.pdf
index eb8840a43..8ec1f1776 100644
Binary files a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/RectangleSvgNodeRendererTest/cmp_basicEllipticalNegativeHeightRoundedRectangle.pdf and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/RectangleSvgNodeRendererTest/cmp_basicEllipticalNegativeHeightRoundedRectangle.pdf differ
diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/RectangleSvgNodeRendererTest/cmp_basicEllipticalNegativeWidthRoundedRectangle.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/RectangleSvgNodeRendererTest/cmp_basicEllipticalNegativeWidthRoundedRectangle.pdf
index 24d05d888..0c25a497a 100644
Binary files a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/RectangleSvgNodeRendererTest/cmp_basicEllipticalNegativeWidthRoundedRectangle.pdf and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/RectangleSvgNodeRendererTest/cmp_basicEllipticalNegativeWidthRoundedRectangle.pdf differ
diff --git a/itext/itext.kernel/itext/kernel/pdf/canvas/PdfCanvas.cs b/itext/itext.kernel/itext/kernel/pdf/canvas/PdfCanvas.cs
index 5e885767d..39d3a34c7 100644
--- a/itext/itext.kernel/itext/kernel/pdf/canvas/PdfCanvas.cs
+++ b/itext/itext.kernel/itext/kernel/pdf/canvas/PdfCanvas.cs
@@ -1052,14 +1052,35 @@ public virtual iText.Kernel.Pdf.Canvas.PdfCanvas Rectangle(iText.Kernel.Geom.Rec
}
/// Draws rounded rectangle.
- /// x coordinate of the starting point.
- /// y coordinate of the starting point.
- /// width.
- /// height.
- /// radius of the arc corner.
- /// current canvas.
+ /// x coordinate of the starting point
+ /// y coordinate of the starting point
+ /// width
+ /// height
+ /// radius of the arc corner
+ /// current canvas
public virtual iText.Kernel.Pdf.Canvas.PdfCanvas RoundRectangle(double x, double y, double width, double height
, double radius) {
+ return RoundRectangle(x, y, width, height, radius, radius, null);
+ }
+
+ /// Draws rounded rectangle.
+ /// x coordinate of the starting point
+ /// y coordinate of the starting point
+ /// width
+ /// height
+ /// x radius of the arc corner
+ /// y radius of the arc corner
+ ///
+ ///
+ ///
+ /// to apply before drawing,
+ /// or
+ ///
+ /// in case transform shouldn't be applied
+ ///
+ /// current canvas
+ public virtual iText.Kernel.Pdf.Canvas.PdfCanvas RoundRectangle(double x, double y, double width, double height
+ , double rx, double ry, AffineTransform transform) {
if (width < 0) {
x += width;
width = -width;
@@ -1068,20 +1089,22 @@ public virtual iText.Kernel.Pdf.Canvas.PdfCanvas RoundRectangle(double x, double
y += height;
height = -height;
}
- if (radius < 0) {
- radius = -radius;
+ if (rx < 0) {
+ rx = -rx;
}
- double curv = 0.4477f;
- MoveTo(x + radius, y);
- LineTo(x + width - radius, y);
- CurveTo(x + width - radius * curv, y, x + width, y + radius * curv, x + width, y + radius);
- LineTo(x + width, y + height - radius);
- CurveTo(x + width, y + height - radius * curv, x + width - radius * curv, y + height, x + width - radius,
- y + height);
- LineTo(x + radius, y + height);
- CurveTo(x + radius * curv, y + height, x, y + height - radius * curv, x, y + height - radius);
- LineTo(x, y + radius);
- CurveTo(x, y + radius * curv, x + radius * curv, y, x + radius, y);
+ if (ry < 0) {
+ ry = -ry;
+ }
+ double[] points = GetEllipseRoundedRectPoints(x, y, width, height, rx, ry);
+ if (transform != null) {
+ transform.Transform(points, 0, points, 0, points.Length / 2);
+ }
+ int i = 0;
+ this.MoveTo(points[i++], points[i++]).LineTo(points[i++], points[i++]).CurveTo(points[i++], points[i++], points
+ [i++], points[i++], points[i++], points[i++]).LineTo(points[i++], points[i++]).CurveTo(points[i++], points
+ [i++], points[i++], points[i++], points[i++], points[i++]).LineTo(points[i++], points[i++]).CurveTo(points
+ [i++], points[i++], points[i++], points[i++], points[i++], points[i++]).LineTo(points[i++], points[i++
+ ]).CurveTo(points[i++], points[i++], points[i++], points[i++], points[i++], points[i]).ClosePath();
return this;
}
@@ -2505,6 +2528,37 @@ private static bool IsIdentityMatrix(float a, float b, float c, float d, float e
&& Math.Abs(1 - d) < IDENTITY_MATRIX_EPS && Math.Abs(e) < IDENTITY_MATRIX_EPS && Math.Abs(f) < IDENTITY_MATRIX_EPS;
}
+ private static double[] GetEllipseRoundedRectPoints(double x, double y, double width, double height, double
+ rx, double ry) {
+ /*
+
+ y+h -> ____________________________
+ / \
+ / \
+ y+h-ry -> / \
+ | |
+ | |
+ | |
+ | |
+ y+ry -> \ /
+ \ /
+ y -> \____________________________/
+ ^ ^ ^ ^
+ x x+rx x+w-rx x+w
+
+ */
+ double[] pt1 = iText.Kernel.Pdf.Canvas.PdfCanvas.BezierArc(x + width - 2 * rx, y, x + width, y + 2 * ry, -
+ 90, 90)[0];
+ double[] pt2 = iText.Kernel.Pdf.Canvas.PdfCanvas.BezierArc(x + width, y + height - 2 * ry, x + width - 2 *
+ rx, y + height, 0, 90)[0];
+ double[] pt3 = iText.Kernel.Pdf.Canvas.PdfCanvas.BezierArc(x + 2 * rx, y + height, x, y + height - 2 * ry,
+ 90, 90)[0];
+ double[] pt4 = iText.Kernel.Pdf.Canvas.PdfCanvas.BezierArc(x, y + 2 * ry, x + 2 * rx, y, 180, 90)[0];
+ return new double[] { x + rx, y, x + width - rx, y, pt1[2], pt1[3], pt1[4], pt1[5], pt1[6], pt1[7], x + width
+ , y + height - ry, pt2[2], pt2[3], pt2[4], pt2[5], pt2[6], pt2[7], x + rx, y + height, pt3[2], pt3[3],
+ pt3[4], pt3[5], pt3[6], pt3[7], x, y + ry, pt4[2], pt4[3], pt4[4], pt4[5], pt4[6], pt4[7] };
+ }
+
/// This method is used to traverse parent tree and begin all layers in it.
///
/// This method is used to traverse parent tree and begin all layers in it.
diff --git a/itext/itext.svg/itext/svg/SvgConstants.cs b/itext/itext.svg/itext/svg/SvgConstants.cs
index 5fae5e4a4..b56195798 100644
--- a/itext/itext.svg/itext/svg/SvgConstants.cs
+++ b/itext/itext.svg/itext/svg/SvgConstants.cs
@@ -606,7 +606,10 @@ public sealed class Attributes : CommonAttributeConstants {
/// Attribute defining the second y coordinate value of a line.
public const String Y2 = "y2";
- /// Attribute defining version
+ /// Attribute defining vector-effect.
+ public const String VECTOR_EFFECT = "vector-effect";
+
+ /// Attribute defining version.
public const String VERSION = "version";
}
@@ -657,9 +660,12 @@ public sealed class Values {
/// Value representing the meet for preserve aspect ratio calculations.
public const String MEET = "meet";
- /// Value representing the "none" value".
+ /// Value representing the "none" value.
public const String NONE = "none";
+ /// Value representing the "non-scaling-stroke" value for vector-effect attribute.
+ public const String NONE_SCALING_STROKE = "non-scaling-stroke";
+
/// Value representing the units relation "objectBoundingBox".
public const String OBJECT_BOUNDING_BOX = "objectBoundingBox";
diff --git a/itext/itext.svg/itext/svg/logs/SvgLogMessageConstant.cs b/itext/itext.svg/itext/svg/logs/SvgLogMessageConstant.cs
index 88f8d78ff..c8f0e237b 100644
--- a/itext/itext.svg/itext/svg/logs/SvgLogMessageConstant.cs
+++ b/itext/itext.svg/itext/svg/logs/SvgLogMessageConstant.cs
@@ -62,6 +62,9 @@ public sealed class SvgLogMessageConstant {
public const String NONINVERTIBLE_TRANSFORMATION_MATRIX_USED_IN_CLIP_PATH = "Non-invertible transformation matrix was used in a clipping path context. Clipped elements may show "
+ "undefined behavior.";
+ public const String NON_INVERTIBLE_TRANSFORMATION_MATRIX_FOR_NON_SCALING_STROKE = "Unable to get inverse transformation matrix and thus apply non-scaling-stroke vector-effect property: "
+ + "some of the transformation matrices, written to the document, have a determinant of zero value.";
+
public const String UNABLE_TO_GET_INVERSE_MATRIX_DUE_TO_ZERO_DETERMINANT = "Unable to get inverse transformation matrix and thus calculate a viewport for the element because some of"
+ " the transformation matrices, which are written to document, have a determinant of zero value. " +
"A bbox of zero values will be used as a viewport for this element.";
diff --git a/itext/itext.svg/itext/svg/renderers/SvgDrawContext.cs b/itext/itext.svg/itext/svg/renderers/SvgDrawContext.cs
index f2d5a5f00..f2aba534e 100644
--- a/itext/itext.svg/itext/svg/renderers/SvgDrawContext.cs
+++ b/itext/itext.svg/itext/svg/renderers/SvgDrawContext.cs
@@ -452,5 +452,28 @@ public virtual AffineTransform GetClippingElementTransform() {
public virtual void ResetClippingElementTransform() {
this.clippingElementTransform.SetToIdentity();
}
+
+ /// Concatenates all transformations applied from the top level of the svg to the current one.
+ ///
+ ///
+ ///
+ /// instance
+ ///
+ public virtual AffineTransform GetConcatenatedTransform() {
+ IList canvasList = new List();
+ int canvasesSize = this.Size();
+ for (int i = 0; i < canvasesSize; i++) {
+ canvasList.Add(this.PopCanvas());
+ }
+ AffineTransform transform = new AffineTransform();
+ for (int i = canvasList.Count - 1; i >= 0; i--) {
+ PdfCanvas pdfCanvas = canvasList[i];
+ Matrix matrix = pdfCanvas.GetGraphicsState().GetCtm();
+ transform.Concatenate(new AffineTransform(matrix.Get(0), matrix.Get(1), matrix.Get(3), matrix.Get(4), matrix
+ .Get(6), matrix.Get(7)));
+ this.PushCanvas(pdfCanvas);
+ }
+ return transform;
+ }
}
}
diff --git a/itext/itext.svg/itext/svg/renderers/impl/AbstractBranchSvgNodeRenderer.cs b/itext/itext.svg/itext/svg/renderers/impl/AbstractBranchSvgNodeRenderer.cs
index 42ba91668..dc605616c 100644
--- a/itext/itext.svg/itext/svg/renderers/impl/AbstractBranchSvgNodeRenderer.cs
+++ b/itext/itext.svg/itext/svg/renderers/impl/AbstractBranchSvgNodeRenderer.cs
@@ -269,19 +269,7 @@ private static bool IsOverflowVisible(AbstractSvgNodeRenderer currentElement) {
/// bbox
///
private static Rectangle GetBBoxAccordingToVisibleOverflow(SvgDrawContext context) {
- IList canvases = new List();
- int canvasesSize = context.Size();
- for (int i = 0; i < canvasesSize; i++) {
- canvases.Add(context.PopCanvas());
- }
- AffineTransform transform = new AffineTransform();
- for (int i = canvases.Count - 1; i >= 0; i--) {
- PdfCanvas canvas = canvases[i];
- Matrix matrix = canvas.GetGraphicsState().GetCtm();
- transform.Concatenate(new AffineTransform(matrix.Get(0), matrix.Get(1), matrix.Get(3), matrix.Get(4), matrix
- .Get(6), matrix.Get(7)));
- context.PushCanvas(canvas);
- }
+ AffineTransform transform = context.GetConcatenatedTransform();
try {
transform = transform.CreateInverse();
}
diff --git a/itext/itext.svg/itext/svg/renderers/impl/AbstractSvgNodeRenderer.cs b/itext/itext.svg/itext/svg/renderers/impl/AbstractSvgNodeRenderer.cs
index 4379741c6..3661779f9 100644
--- a/itext/itext.svg/itext/svg/renderers/impl/AbstractSvgNodeRenderer.cs
+++ b/itext/itext.svg/itext/svg/renderers/impl/AbstractSvgNodeRenderer.cs
@@ -22,6 +22,8 @@ You should have received a copy of the GNU Affero General Public License
*/
using System;
using System.Collections.Generic;
+using Microsoft.Extensions.Logging;
+using iText.Commons;
using iText.Kernel.Colors;
using iText.Kernel.Geom;
using iText.Kernel.Pdf.Canvas;
@@ -34,6 +36,7 @@ You should have received a copy of the GNU Affero General Public License
using iText.Svg;
using iText.Svg.Css;
using iText.Svg.Css.Impl;
+using iText.Svg.Logs;
using iText.Svg.Renderers;
using iText.Svg.Utils;
@@ -46,6 +49,8 @@ public abstract class AbstractSvgNodeRenderer : ISvgNodeRenderer {
private static readonly MarkerVertexType[] MARKER_VERTEX_TYPES = new MarkerVertexType[] { MarkerVertexType
.MARKER_START, MarkerVertexType.MARKER_MID, MarkerVertexType.MARKER_END };
+ private static readonly ILogger LOGGER = ITextLogManager.GetLogger(typeof(AbstractSvgNodeRenderer));
+
/// Map that contains attributes and styles used for drawing operations.
protected internal IDictionary attributesAndStyles;
@@ -275,6 +280,34 @@ internal virtual ClipPathSvgNodeRenderer GetParentClipPath() {
}
//\endcond
+//\cond DO_NOT_DOCUMENT
+ ///
+ /// Applies non-scaling-stroke vector-effect to this renderer by concatenating all transformations applied
+ /// from the top level of the svg to the current one, inverting it and applying to the current canvas.
+ ///
+ /// the SVG draw context
+ ///
+ /// the transformation that was inverted and applied to this renderer
+ /// to achieve non-scaling-stroke vector-effect
+ ///
+ internal virtual AffineTransform ApplyNonScalingStrokeTransform(SvgDrawContext context) {
+ AffineTransform transform = null;
+ bool isNonScalingStroke = doStroke && SvgConstants.Values.NONE_SCALING_STROKE.Equals(GetAttribute(SvgConstants.Attributes
+ .VECTOR_EFFECT));
+ if (isNonScalingStroke) {
+ transform = context.GetConcatenatedTransform();
+ try {
+ context.GetCurrentCanvas().ConcatMatrix(transform.CreateInverse());
+ }
+ catch (NoninvertibleTransformException) {
+ LOGGER.LogWarning(SvgLogMessageConstant.NON_INVERTIBLE_TRANSFORMATION_MATRIX_FOR_NON_SCALING_STROKE);
+ transform = null;
+ }
+ }
+ return transform;
+ }
+//\endcond
+
//\cond DO_NOT_DOCUMENT
/// Calculate the transformation for the viewport based on the context.
///
@@ -587,7 +620,12 @@ private float GetOpacityByAttributeName(String attributeName, float generalOpaci
opacityValue = CssDimensionParsingUtils.ParseRelativeValue(opacityStr, 1f);
}
else {
- opacityValue = float.Parse(opacityStr, System.Globalization.CultureInfo.InvariantCulture);
+ if (CssTypesValidationUtils.IsNumber(opacityStr)) {
+ opacityValue = (float)CssDimensionParsingUtils.ParseFloat(opacityStr);
+ }
+ else {
+ opacityValue = 1;
+ }
}
opacity *= opacityValue;
}
@@ -605,7 +643,7 @@ private bool DrawInClipPath(SvgDrawContext context) {
SvgNodeRendererInheritanceResolver.ApplyInheritanceToSubTree(this, clipPath, context.GetCssContext());
clipPath.SetClippedRenderer(this);
clipPath.Draw(context);
- return !clipPath.GetChildren().IsEmpty();
+ return true;
}
}
return false;
diff --git a/itext/itext.svg/itext/svg/renderers/impl/EllipseSvgNodeRenderer.cs b/itext/itext.svg/itext/svg/renderers/impl/EllipseSvgNodeRenderer.cs
index bc0ebfa96..ee528994b 100644
--- a/itext/itext.svg/itext/svg/renderers/impl/EllipseSvgNodeRenderer.cs
+++ b/itext/itext.svg/itext/svg/renderers/impl/EllipseSvgNodeRenderer.cs
@@ -54,9 +54,14 @@ protected internal override void DoDraw(SvgDrawContext context) {
cv.WriteLiteral("% ellipse\n");
if (SetParameters(context)) {
// Use double type locally to have better precision of the result after applying arithmetic operations
- cv.MoveTo((double)cx + (double)rx, cy);
+ double[] startPoint = new double[] { (double)cx + (double)rx, cy };
+ AffineTransform transform = ApplyNonScalingStrokeTransform(context);
+ if (transform != null) {
+ transform.Transform(startPoint, 0, startPoint, 0, startPoint.Length / 2);
+ }
+ cv.MoveTo(startPoint[0], startPoint[1]);
DrawUtils.Arc((double)cx - (double)rx, (double)cy - (double)ry, (double)cx + (double)rx, (double)cy + (double
- )ry, 0, 360, cv);
+ )ry, 0, 360, cv, transform);
}
}
diff --git a/itext/itext.svg/itext/svg/renderers/impl/ImageSvgNodeRenderer.cs b/itext/itext.svg/itext/svg/renderers/impl/ImageSvgNodeRenderer.cs
index ad40bde70..79b1bad65 100644
--- a/itext/itext.svg/itext/svg/renderers/impl/ImageSvgNodeRenderer.cs
+++ b/itext/itext.svg/itext/svg/renderers/impl/ImageSvgNodeRenderer.cs
@@ -50,7 +50,10 @@ protected internal override void DoDraw(SvgDrawContext context) {
if (resourceResolver == null || this.attributesAndStyles == null) {
return;
}
- String uri = this.attributesAndStyles.Get(SvgConstants.Attributes.XLINK_HREF);
+ String uri = this.attributesAndStyles.Get(SvgConstants.Attributes.HREF);
+ if (uri == null) {
+ uri = this.attributesAndStyles.Get(SvgConstants.Attributes.XLINK_HREF);
+ }
PdfXObject xObject = resourceResolver.RetrieveImage(uri);
if (xObject == null) {
return;
diff --git a/itext/itext.svg/itext/svg/renderers/impl/LineSvgNodeRenderer.cs b/itext/itext.svg/itext/svg/renderers/impl/LineSvgNodeRenderer.cs
index 839e018a8..82dc5fd25 100644
--- a/itext/itext.svg/itext/svg/renderers/impl/LineSvgNodeRenderer.cs
+++ b/itext/itext.svg/itext/svg/renderers/impl/LineSvgNodeRenderer.cs
@@ -47,7 +47,13 @@ protected internal override void DoDraw(SvgDrawContext context) {
PdfCanvas canvas = context.GetCurrentCanvas();
canvas.WriteLiteral("% line\n");
if (SetParameters(context)) {
- canvas.MoveTo(x1, y1).LineTo(x2, y2);
+ float[] points = new float[] { x1, y1, x2, y2 };
+ AffineTransform transform = ApplyNonScalingStrokeTransform(context);
+ if (transform != null) {
+ transform.Transform(points, 0, points, 0, points.Length / 2);
+ }
+ int i = 0;
+ canvas.MoveTo(points[i++], points[i++]).LineTo(points[i++], points[i]);
}
}
diff --git a/itext/itext.svg/itext/svg/renderers/impl/PathSvgNodeRenderer.cs b/itext/itext.svg/itext/svg/renderers/impl/PathSvgNodeRenderer.cs
index 626a81510..dd43f9aa9 100644
--- a/itext/itext.svg/itext/svg/renderers/impl/PathSvgNodeRenderer.cs
+++ b/itext/itext.svg/itext/svg/renderers/impl/PathSvgNodeRenderer.cs
@@ -110,11 +110,13 @@ public class PathSvgNodeRenderer : AbstractSvgNodeRenderer, IMarkerCapable {
protected internal override void DoDraw(SvgDrawContext context) {
PdfCanvas canvas = context.GetCurrentCanvas();
canvas.WriteLiteral("% path\n");
+ AffineTransform transform = ApplyNonScalingStrokeTransform(context);
foreach (IPathShape item in GetShapes()) {
if (item is AbstractPathShape) {
AbstractPathShape shape = (AbstractPathShape)item;
shape.SetParent(this);
shape.SetContext(context);
+ shape.SetTransform(transform);
}
item.Draw(context.GetCurrentCanvas());
}
diff --git a/itext/itext.svg/itext/svg/renderers/impl/PolylineSvgNodeRenderer.cs b/itext/itext.svg/itext/svg/renderers/impl/PolylineSvgNodeRenderer.cs
index 05a22a835..b1356aed3 100644
--- a/itext/itext.svg/itext/svg/renderers/impl/PolylineSvgNodeRenderer.cs
+++ b/itext/itext.svg/itext/svg/renderers/impl/PolylineSvgNodeRenderer.cs
@@ -22,6 +22,7 @@ You should have received a copy of the GNU Affero General Public License
*/
using System;
using System.Collections.Generic;
+using iText.Commons.Utils;
using iText.Kernel.Geom;
using iText.Kernel.Pdf.Canvas;
using iText.StyledXmlParser.Css.Util;
@@ -120,6 +121,12 @@ protected internal override void DoDraw(SvgDrawContext context) {
PdfCanvas canvas = context.GetCurrentCanvas();
canvas.WriteLiteral("% polyline\n");
if (points.Count > 1) {
+ AffineTransform transform = ApplyNonScalingStrokeTransform(context);
+ if (transform != null) {
+ Point[] pt = points.ToArray(new Point[0]);
+ transform.Transform(pt, 0, pt, 0, pt.Length);
+ points = JavaUtil.ArraysAsList(pt);
+ }
Point currentPoint = points[0];
canvas.MoveTo(currentPoint.GetX(), currentPoint.GetY());
for (int x = 1; x < points.Count; x++) {
diff --git a/itext/itext.svg/itext/svg/renderers/impl/RectangleSvgNodeRenderer.cs b/itext/itext.svg/itext/svg/renderers/impl/RectangleSvgNodeRenderer.cs
index 347c46222..b6fc371d8 100644
--- a/itext/itext.svg/itext/svg/renderers/impl/RectangleSvgNodeRenderer.cs
+++ b/itext/itext.svg/itext/svg/renderers/impl/RectangleSvgNodeRenderer.cs
@@ -59,46 +59,31 @@ protected internal override void DoDraw(SvgDrawContext context) {
cv.WriteLiteral("% rect\n");
SetParameters(context);
bool singleValuePresent = (rxPresent && !ryPresent) || (!rxPresent && ryPresent);
+ AffineTransform transform = ApplyNonScalingStrokeTransform(context);
if (!rxPresent && !ryPresent) {
- cv.Rectangle(x, y, width, height);
+ Point[] points = new Rectangle(x, y, width, height).ToPointsArray();
+ if (transform != null) {
+ transform.Transform(points, 0, points, 0, points.Length);
+ if (Math.Abs(transform.GetShearX()) > 0 || Math.Abs(transform.GetShearY()) > 0) {
+ int i = 0;
+ cv.MoveTo(points[i].GetX(), points[i++].GetY()).LineTo(points[i].GetX(), points[i++].GetY()).LineTo(points
+ [i].GetX(), points[i++].GetY()).LineTo(points[i].GetX(), points[i].GetY()).ClosePath();
+ return;
+ }
+ }
+ cv.Rectangle(points[0].GetX(), points[0].GetY(), points[1].GetX() - points[0].GetX(), points[2].GetY() - points
+ [0].GetY());
}
else {
if (singleValuePresent) {
cv.WriteLiteral("% circle rounded rect\n");
- // only look for radius in case of circular rounding
+ // Only look for radius in case of circular rounding.
float radius = FindCircularRadius(rx, ry, width, height);
- cv.RoundRectangle(x, y, width, height, radius);
+ cv.RoundRectangle(x, y, width, height, radius, radius, transform);
}
else {
cv.WriteLiteral("% ellipse rounded rect\n");
- // TODO (DEVSIX-1878): this should actually be refactored into PdfCanvas.roundRectangle()
- /*
-
- y+h -> ____________________________
- / \
- / \
- y+h-ry -> / \
- | |
- | |
- | |
- | |
- y+ry -> \ /
- \ /
- y -> \____________________________/
- ^ ^ ^ ^
- x x+rx x+w-rx x+w
-
- */
- cv.MoveTo(x + rx, y);
- cv.LineTo(x + width - rx, y);
- Arc(x + width - 2 * rx, y, x + width, y + 2 * ry, -90, 90, cv);
- cv.LineTo(x + width, y + height - ry);
- Arc(x + width, y + height - 2 * ry, x + width - 2 * rx, y + height, 0, 90, cv);
- cv.LineTo(x + rx, y + height);
- Arc(x + 2 * rx, y + height, x, y + height - 2 * ry, 90, 90, cv);
- cv.LineTo(x, y + ry);
- Arc(x, y + 2 * ry, x + 2 * rx, y, 180, 90, cv);
- cv.ClosePath();
+ cv.RoundRectangle(x, y, width, height, rx, ry, transform);
}
}
}
@@ -129,17 +114,6 @@ private void SetParameters(SvgDrawContext context) {
}
}
- private void Arc(float x1, float y1, float x2, float y2, float startAng, float extent, PdfCanvas cv) {
- IList ar = PdfCanvas.BezierArc(x1, y1, x2, y2, startAng, extent);
- if (!ar.IsEmpty()) {
- double[] pt;
- for (int k = 0; k < ar.Count; ++k) {
- pt = ar[k];
- cv.CurveTo(pt[2], pt[3], pt[4], pt[5], pt[6], pt[7]);
- }
- }
- }
-
//\cond DO_NOT_DOCUMENT
///
/// a radius must be positive, and cannot be more than half the distance in
diff --git a/itext/itext.svg/itext/svg/renderers/path/impl/AbstractPathShape.cs b/itext/itext.svg/itext/svg/renderers/path/impl/AbstractPathShape.cs
index e9a6750e2..9bfadf237 100644
--- a/itext/itext.svg/itext/svg/renderers/path/impl/AbstractPathShape.cs
+++ b/itext/itext.svg/itext/svg/renderers/path/impl/AbstractPathShape.cs
@@ -35,6 +35,8 @@ namespace iText.Svg.Renderers.Path.Impl {
public abstract class AbstractPathShape : IPathShape {
private PathSvgNodeRenderer parent;
+ private AffineTransform transform = null;
+
/// The properties of this shape.
protected internal IDictionary properties;
@@ -109,6 +111,20 @@ public virtual void SetContext(SvgDrawContext context) {
this.context = context;
}
+ ///
+ /// Sets
+ ///
+ /// to apply before drawing the shape.
+ ///
+ ///
+ ///
+ ///
+ /// to apply before drawing
+ ///
+ public virtual void SetTransform(AffineTransform transform) {
+ this.transform = transform;
+ }
+
/// Parse x axis length value.
///
///
@@ -131,6 +147,14 @@ protected internal virtual float ParseVerticalLength(String length) {
return SvgCssUtils.ParseAbsoluteVerticalLength(parent, length, 0.0F, context);
}
+//\cond DO_NOT_DOCUMENT
+ internal virtual void ApplyTransform(double[] points) {
+ if (transform != null) {
+ transform.Transform(points, 0, points, 0, points.Length / 2);
+ }
+ }
+//\endcond
+
public abstract void SetCoordinates(String[] arg1, Point arg2);
}
}
diff --git a/itext/itext.svg/itext/svg/renderers/path/impl/CurveTo.cs b/itext/itext.svg/itext/svg/renderers/path/impl/CurveTo.cs
index 57eb45488..86118446e 100644
--- a/itext/itext.svg/itext/svg/renderers/path/impl/CurveTo.cs
+++ b/itext/itext.svg/itext/svg/renderers/path/impl/CurveTo.cs
@@ -49,13 +49,17 @@ public CurveTo(bool relative, IOperatorConverter copier)
}
public override void Draw() {
- float x1 = ParseHorizontalLength(coordinates[0]);
- float y1 = ParseVerticalLength(coordinates[1]);
- float x2 = ParseHorizontalLength(coordinates[2]);
- float y2 = ParseVerticalLength(coordinates[3]);
- float x = ParseHorizontalLength(coordinates[4]);
- float y = ParseVerticalLength(coordinates[5]);
- context.GetCurrentCanvas().CurveTo(x1, y1, x2, y2, x, y);
+ double x1 = ParseHorizontalLength(coordinates[0]);
+ double y1 = ParseVerticalLength(coordinates[1]);
+ double x2 = ParseHorizontalLength(coordinates[2]);
+ double y2 = ParseVerticalLength(coordinates[3]);
+ double x = ParseHorizontalLength(coordinates[4]);
+ double y = ParseVerticalLength(coordinates[5]);
+ double[] points = new double[] { x1, y1, x2, y2, x, y };
+ ApplyTransform(points);
+ int i = 0;
+ context.GetCurrentCanvas().CurveTo(points[i++], points[i++], points[i++], points[i++], points[i++], points
+ [i]);
}
public override void SetCoordinates(String[] inputCoordinates, Point startPoint) {
diff --git a/itext/itext.svg/itext/svg/renderers/path/impl/EllipticalCurveTo.cs b/itext/itext.svg/itext/svg/renderers/path/impl/EllipticalCurveTo.cs
index 49d0448da..d25336962 100644
--- a/itext/itext.svg/itext/svg/renderers/path/impl/EllipticalCurveTo.cs
+++ b/itext/itext.svg/itext/svg/renderers/path/impl/EllipticalCurveTo.cs
@@ -99,7 +99,9 @@ public override void Draw() {
/* edge case: If rx = 0 or ry = 0 then this arc is treated as a straight line segment (a "lineto")
* joining the endpoints.
*/
- context.GetCurrentCanvas().LineTo(end.GetX(), end.GetY());
+ double[] points = new double[] { end.GetX(), end.GetY() };
+ ApplyTransform(points);
+ context.GetCurrentCanvas().LineTo(points[0], points[1]);
}
else {
/* This is the first step of calculating a rotated elliptical path.
@@ -166,8 +168,11 @@ internal virtual String[] GetCoordinates() {
}
//\endcond
- private static void DrawCurve(PdfCanvas canvas, Point cp1, Point cp2, Point end) {
- canvas.CurveTo(cp1.GetX(), cp1.GetY(), cp2.GetX(), cp2.GetY(), end.GetX(), end.GetY());
+ private void DrawCurve(PdfCanvas canvas, Point cp1, Point cp2, Point end) {
+ double[] points = new double[] { cp1.GetX(), cp1.GetY(), cp2.GetX(), cp2.GetY(), end.GetX(), end.GetY() };
+ ApplyTransform(points);
+ int i = 0;
+ canvas.CurveTo(points[i++], points[i++], points[i++], points[i++], points[i++], points[i]);
}
private Point[][] MakePoints(IList input) {
diff --git a/itext/itext.svg/itext/svg/renderers/path/impl/LineTo.cs b/itext/itext.svg/itext/svg/renderers/path/impl/LineTo.cs
index 1107951fc..f3261e073 100644
--- a/itext/itext.svg/itext/svg/renderers/path/impl/LineTo.cs
+++ b/itext/itext.svg/itext/svg/renderers/path/impl/LineTo.cs
@@ -41,9 +41,11 @@ public LineTo(bool relative)
}
public override void Draw() {
- float x = ParseHorizontalLength(coordinates[0]);
- float y = ParseVerticalLength(coordinates[1]);
- context.GetCurrentCanvas().LineTo(x, y);
+ double x = ParseHorizontalLength(coordinates[0]);
+ double y = ParseVerticalLength(coordinates[1]);
+ double[] points = new double[] { x, y };
+ ApplyTransform(points);
+ context.GetCurrentCanvas().LineTo(points[0], points[1]);
}
public override void SetCoordinates(String[] inputCoordinates, Point startPoint) {
diff --git a/itext/itext.svg/itext/svg/renderers/path/impl/MoveTo.cs b/itext/itext.svg/itext/svg/renderers/path/impl/MoveTo.cs
index d4e1acf76..96f9aaa6d 100644
--- a/itext/itext.svg/itext/svg/renderers/path/impl/MoveTo.cs
+++ b/itext/itext.svg/itext/svg/renderers/path/impl/MoveTo.cs
@@ -41,9 +41,11 @@ public MoveTo(bool relative)
}
public override void Draw() {
- float x = ParseHorizontalLength(coordinates[0]);
- float y = ParseVerticalLength(coordinates[1]);
- context.GetCurrentCanvas().MoveTo(x, y);
+ double x = ParseHorizontalLength(coordinates[0]);
+ double y = ParseVerticalLength(coordinates[1]);
+ double[] points = new double[] { x, y };
+ ApplyTransform(points);
+ context.GetCurrentCanvas().MoveTo(points[0], points[1]);
}
public override void SetCoordinates(String[] inputCoordinates, Point startPoint) {
diff --git a/itext/itext.svg/itext/svg/renderers/path/impl/QuadraticCurveTo.cs b/itext/itext.svg/itext/svg/renderers/path/impl/QuadraticCurveTo.cs
index d6dacaa6e..bba158921 100644
--- a/itext/itext.svg/itext/svg/renderers/path/impl/QuadraticCurveTo.cs
+++ b/itext/itext.svg/itext/svg/renderers/path/impl/QuadraticCurveTo.cs
@@ -49,11 +49,14 @@ public QuadraticCurveTo(bool relative, IOperatorConverter copier)
/// Draws a quadratic Bezier curve from the current point to (x,y) using (x1,y1) as the control point
///
public override void Draw() {
- float x1 = ParseHorizontalLength(coordinates[0]);
- float y1 = ParseVerticalLength(coordinates[1]);
- float x = ParseHorizontalLength(coordinates[2]);
- float y = ParseVerticalLength(coordinates[3]);
- context.GetCurrentCanvas().CurveTo(x1, y1, x, y);
+ double x1 = ParseHorizontalLength(coordinates[0]);
+ double y1 = ParseVerticalLength(coordinates[1]);
+ double x = ParseHorizontalLength(coordinates[2]);
+ double y = ParseVerticalLength(coordinates[3]);
+ double[] points = new double[] { x1, y1, x, y };
+ ApplyTransform(points);
+ int i = 0;
+ context.GetCurrentCanvas().CurveTo(points[i++], points[i++], points[i++], points[i]);
}
public override void SetCoordinates(String[] inputCoordinates, Point startPoint) {
diff --git a/itext/itext.svg/itext/svg/utils/DrawUtils.cs b/itext/itext.svg/itext/svg/utils/DrawUtils.cs
index 830d6934a..7c41a039e 100644
--- a/itext/itext.svg/itext/svg/utils/DrawUtils.cs
+++ b/itext/itext.svg/itext/svg/utils/DrawUtils.cs
@@ -22,6 +22,7 @@ You should have received a copy of the GNU Affero General Public License
*/
using System;
using System.Collections.Generic;
+using iText.Kernel.Geom;
using iText.Kernel.Pdf.Canvas;
using iText.Svg;
@@ -52,9 +53,41 @@ private DrawUtils() {
/// canvas to paint on
public static void Arc(double x1, double y1, double x2, double y2, double startAng, double extent, PdfCanvas
cv) {
+ Arc(x1, y1, x2, y2, startAng, extent, cv, null);
+ }
+
+ ///
+ /// Draw an arc on the passed canvas with provided transform,
+ /// enclosed by the rectangle for which two opposite corners are specified.
+ ///
+ ///
+ /// Draw an arc on the passed canvas with provided transform,
+ /// enclosed by the rectangle for which two opposite corners are specified.
+ /// The arc starts at the passed starting angle and extends to the starting angle + extent
+ ///
+ /// corner-coordinate of the enclosing rectangle, first corner
+ /// corner-coordinate of the enclosing rectangle, first corner
+ /// corner-coordinate of the enclosing rectangle, second corner
+ /// corner-coordinate of the enclosing rectangle, second corner
+ /// starting angle in degrees
+ /// extent of the arc
+ /// canvas to paint on
+ ///
+ ///
+ ///
+ /// to apply before drawing,
+ /// or
+ ///
+ /// in case transform shouldn't be applied
+ ///
+ public static void Arc(double x1, double y1, double x2, double y2, double startAng, double extent, PdfCanvas
+ cv, AffineTransform transform) {
IList ar = PdfCanvas.BezierArc(x1, y1, x2, y2, startAng, extent);
if (!ar.IsEmpty()) {
foreach (double[] pt in ar) {
+ if (transform != null) {
+ transform.Transform(pt, 0, pt, 0, pt.Length / 2);
+ }
cv.CurveTo(pt[2], pt[3], pt[4], pt[5], pt[6], pt[7]);
}
}
diff --git a/port-hash b/port-hash
index 82e8c5e5e..3566ace11 100644
--- a/port-hash
+++ b/port-hash
@@ -1 +1 @@
-ce35dbce51bd8c3f1b01e78313f1f5a2a02201ff
+cbb82b1d822c93fa6b76c4fb7b35c2e4182ea809