From ba60348403b952b56838e516a4541d35039a6cec Mon Sep 17 00:00:00 2001 From: Dmitry Radchuk Date: Fri, 27 Dec 2024 10:11:28 +0000 Subject: [PATCH 1/2] Support marker-mid property DEVSIX-3397 Autoported commit. Original commit hash: [7c2649724] --- .../itext/kernel/geom/PointTest.cs | 7 ++ .../shorthand/MarkerShorthandResolverTest.cs | 72 ++++++++++++++++++ .../MarkerSvgNodeRendererIntegrationTest.cs | 37 +++++++-- .../cmp_marker.pdf | Bin 2165 -> 2463 bytes ..._markerEspecialMarkerWidthHeightValues.pdf | Bin 1443 -> 1435 bytes .../cmp_markerInLineElement.pdf | Bin 2300 -> 2300 bytes .../cmp_markerInPath.pdf | Bin 2698 -> 6505 bytes .../cmp_markerInPathWithAngledMarker.pdf | Bin 0 -> 5406 bytes .../cmp_markerInPolygonElement.pdf | Bin 2334 -> 4190 bytes ...markerInPolygonElementWithComplexAngle.pdf | Bin 0 -> 2377 bytes .../cmp_markerInPolylineElement.pdf | Bin 2298 -> 2762 bytes .../cmp_markerShorthandInPolyline.pdf | Bin 0 -> 2484 bytes .../cmp_markerShorthandInheritance.pdf | Bin 0 -> 2490 bytes .../cmp_markerShorthandTagInheritance.pdf | Bin 0 -> 2490 bytes .../cmp_markerShorthandWithFillAndStroke.pdf | Bin 0 -> 6674 bytes .../markerInPathWithAngledMarker.svg | 25 ++++++ ...markerInPolygonElementWithComplexAngle.svg | 13 ++++ .../markerRefXY.svg | 18 ++--- .../markerShorthandInPolyline.svg | 6 ++ .../markerShorthandInheritance.svg | 9 +++ .../markerShorthandTagInheritance.svg | 16 ++++ .../markerShorthandWithFillAndStroke.svg | 22 ++++++ .../parentStrokeWidthIsMetricValues.svg | 8 +- .../strokeWidthMeasureUnitsTest.svg | 40 +++++----- itext/itext.kernel/itext/kernel/geom/Point.cs | 16 ++++ .../styledxmlparser/css/CommonCssConstants.cs | 12 +++ .../shorthand/ShorthandResolverFactory.cs | 1 + .../shorthand/impl/MarkerShorthandResolver.cs | 46 +++++++++++ itext/itext.svg/itext/svg/SvgConstants.cs | 3 + .../itext/svg/css/impl/SvgStyleResolver.cs | 9 +-- .../renderers/impl/AbstractSvgNodeRenderer.cs | 6 +- .../renderers/impl/MarkerSvgNodeRenderer.cs | 37 +++++++++ .../svg/renderers/impl/PathSvgNodeRenderer.cs | 54 +++++++------ .../renderers/impl/PolylineSvgNodeRenderer.cs | 62 ++++++++------- port-hash | 2 +- 35 files changed, 417 insertions(+), 104 deletions(-) create mode 100644 itext.tests/itext.styledxmlparser.tests/itext/styledxmlparser/css/resolve/shorthand/MarkerShorthandResolverTest.cs create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/cmp_markerInPathWithAngledMarker.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/cmp_markerInPolygonElementWithComplexAngle.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/cmp_markerShorthandInPolyline.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/cmp_markerShorthandInheritance.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/cmp_markerShorthandTagInheritance.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/cmp_markerShorthandWithFillAndStroke.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerInPathWithAngledMarker.svg create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerInPolygonElementWithComplexAngle.svg create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerShorthandInPolyline.svg create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerShorthandInheritance.svg create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerShorthandTagInheritance.svg create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerShorthandWithFillAndStroke.svg create mode 100644 itext/itext.styledxmlparser/itext/styledxmlparser/css/resolve/shorthand/impl/MarkerShorthandResolver.cs diff --git a/itext.tests/itext.kernel.tests/itext/kernel/geom/PointTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/geom/PointTest.cs index a4bb8d3670..8f2288d203 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/geom/PointTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/geom/PointTest.cs @@ -35,6 +35,13 @@ public virtual void DefaultConstructorTest() { NUnit.Framework.Assert.AreEqual(0, first.GetY(), EPSILON_COMPARISON); } + [NUnit.Framework.Test] + public virtual void CopyConstructorTest() { + Point first = new Point(new Point(4.0, 5.0)); + NUnit.Framework.Assert.AreEqual(4.0, first.GetX(), EPSILON_COMPARISON); + NUnit.Framework.Assert.AreEqual(5.0, first.GetY(), EPSILON_COMPARISON); + } + [NUnit.Framework.Test] public virtual void DoubleParamConstructorTest() { Point first = new Point(0.13, 1.1); diff --git a/itext.tests/itext.styledxmlparser.tests/itext/styledxmlparser/css/resolve/shorthand/MarkerShorthandResolverTest.cs b/itext.tests/itext.styledxmlparser.tests/itext/styledxmlparser/css/resolve/shorthand/MarkerShorthandResolverTest.cs new file mode 100644 index 0000000000..7926e59bea --- /dev/null +++ b/itext.tests/itext.styledxmlparser.tests/itext/styledxmlparser/css/resolve/shorthand/MarkerShorthandResolverTest.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using iText.Commons.Utils; +using iText.StyledXmlParser.Css; +using iText.Test; +using iText.Test.Attributes; + +namespace iText.StyledXmlParser.Css.Resolve.Shorthand { + [NUnit.Framework.Category("UnitTest")] + public class MarkerShorthandResolverTest : ExtendedITextTest { + [NUnit.Framework.Test] + public virtual void InitialValueTest() { + String shorthandExpression = "initial"; + ICollection expectedResolvedProperties = new HashSet(JavaUtil.ArraysAsList("marker-start: initial" + , "marker-mid: initial", "marker-end: initial")); + IShorthandResolver markerResolver = ShorthandResolverFactory.GetShorthandResolver(CommonCssConstants.MARKER + ); + NUnit.Framework.Assert.IsNotNull(markerResolver); + IList resolvedShorthandProps = markerResolver.ResolveShorthand(shorthandExpression); + CssShorthandResolverTest.CompareResolvedProps(resolvedShorthandProps, expectedResolvedProperties); + } + + [NUnit.Framework.Test] + [LogMessage(iText.StyledXmlParser.Logs.StyledXmlParserLogMessageConstant.SHORTHAND_PROPERTY_CANNOT_BE_EMPTY + )] + public virtual void EmptyValueTest() { + String shorthandExpression = " "; + ICollection expectedResolvedProperties = new HashSet(); + IShorthandResolver markerResolver = ShorthandResolverFactory.GetShorthandResolver(CommonCssConstants.MARKER + ); + NUnit.Framework.Assert.IsNotNull(markerResolver); + IList resolvedShorthandProps = markerResolver.ResolveShorthand(shorthandExpression); + CssShorthandResolverTest.CompareResolvedProps(resolvedShorthandProps, expectedResolvedProperties); + } + + [NUnit.Framework.Test] + [LogMessage(iText.StyledXmlParser.Logs.StyledXmlParserLogMessageConstant.INVALID_CSS_PROPERTY_DECLARATION)] + public virtual void InvalidValueTest() { + String shorthandExpression = "junk"; + ICollection expectedResolvedProperties = new HashSet(); + IShorthandResolver markerResolver = ShorthandResolverFactory.GetShorthandResolver(CommonCssConstants.MARKER + ); + NUnit.Framework.Assert.IsNotNull(markerResolver); + IList resolvedShorthandProps = markerResolver.ResolveShorthand(shorthandExpression); + CssShorthandResolverTest.CompareResolvedProps(resolvedShorthandProps, expectedResolvedProperties); + } + + [NUnit.Framework.Test] + [LogMessage(iText.StyledXmlParser.Logs.StyledXmlParserLogMessageConstant.INVALID_CSS_PROPERTY_DECLARATION)] + public virtual void InvalidUrlTest() { + String shorthandExpression = "url(test"; + ICollection expectedResolvedProperties = new HashSet(); + IShorthandResolver markerResolver = ShorthandResolverFactory.GetShorthandResolver(CommonCssConstants.MARKER + ); + NUnit.Framework.Assert.IsNotNull(markerResolver); + IList resolvedShorthandProps = markerResolver.ResolveShorthand(shorthandExpression); + CssShorthandResolverTest.CompareResolvedProps(resolvedShorthandProps, expectedResolvedProperties); + } + + [NUnit.Framework.Test] + public virtual void ValidTest() { + String shorthandExpression = "url(markers.svg#arrow)"; + ICollection expectedResolvedProperties = new HashSet(JavaUtil.ArraysAsList("marker-start: url(markers.svg#arrow)" + , "marker-mid: url(markers.svg#arrow)", "marker-end: url(markers.svg#arrow)")); + IShorthandResolver markerResolver = ShorthandResolverFactory.GetShorthandResolver(CommonCssConstants.MARKER + ); + NUnit.Framework.Assert.IsNotNull(markerResolver); + IList resolvedShorthandProps = markerResolver.ResolveShorthand(shorthandExpression); + CssShorthandResolverTest.CompareResolvedProps(resolvedShorthandProps, expectedResolvedProperties); + } + } +} diff --git a/itext.tests/itext.svg.tests/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest.cs b/itext.tests/itext.svg.tests/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest.cs index b31c0fbd8d..aeb9e2f1a8 100644 --- a/itext.tests/itext.svg.tests/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest.cs +++ b/itext.tests/itext.svg.tests/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest.cs @@ -109,34 +109,61 @@ public virtual void MarkerPathPreserveAspectRatioTest() { // Markers in different elements [NUnit.Framework.Test] public virtual void MarkerTest() { - // TODO: update when DEVSIX-3397 will be closed ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "marker"); } [NUnit.Framework.Test] public virtual void MarkerInLineElementTest() { - // TODO: update when DEVSIX-3397 will be closed ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "markerInLineElement"); } [NUnit.Framework.Test] public virtual void MarkerInPolylineElementTest() { - // TODO: update when DEVSIX-3397 will be closed ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "markerInPolylineElement"); } [NUnit.Framework.Test] public virtual void MarkerInPolygonElementTest() { - // TODO: update when DEVSIX-3397, DEVSIX-2719 will be closed + // TODO: update when DEVSIX-2719 will be closed ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "markerInPolygonElement"); } + [NUnit.Framework.Test] + public virtual void MarkerInPolygonElementWithComplexAngleTest() { + ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "markerInPolygonElementWithComplexAngle"); + } + + [NUnit.Framework.Test] + public virtual void MarkerShorthandWithFillAndStrokeTest() { + ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "markerShorthandWithFillAndStroke"); + } + [NUnit.Framework.Test] public virtual void MarkerInPathTest() { - // TODO: update when DEVSIX-3397 will be closed ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "markerInPath"); } + [NUnit.Framework.Test] + public virtual void MarkerInPathWithAngledMarkerTest() { + // TODO: update when DEVSIX-8749 will be closed + ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "markerInPathWithAngledMarker"); + } + + [NUnit.Framework.Test] + public virtual void MarkerShorthandInPolylineTest() { + ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "markerShorthandInPolyline"); + } + + [NUnit.Framework.Test] + public virtual void MarkerShorthandInheritanceTest() { + ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "markerShorthandInheritance"); + } + + [NUnit.Framework.Test] + public virtual void MarkerShorthandTagInheritanceTest() { + ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "markerShorthandTagInheritance"); + } + [NUnit.Framework.Test] public virtual void MarkerUnitsTest() { ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "markerUnits"); diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/cmp_marker.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/cmp_marker.pdf index db10428ad0a1fb0d6b21db07247032fbcca83bb8..2effb1d008b714b9b97d00921bd7ea397279bb4c 100644 GIT binary patch delta 553 zcmb_YyGjE=6lHg##sMD?M8v{Dh=r2P+?k!nLP+BaZA4=sh{f(aB%oPXQizTE4f6ro zX{VS!@n7sLTotsi6HjqC_i!JF`#O8ucv=bSlo0}qr#=oAzKhXba2G@@Rem~L^i$Ey zM0@L;VIY1rT=VPEi+_%mCTUDLZdL4eYs>yEI;}IjQJ{Ua?;pdt(RHmEgo60{vEF=X z^$-zEFpDMsqS7Mw(HB-*Z)y$i$3_A8?eT{zDkvr&zypjv1pyB7mnT&6;|9lt?@Now;FeQj&X_{MYsRIIpW=cwGX(nB61>{_CnP$L^qQ)dPlU8VbB{Wmj5X*U@ zGc0M`2q*2Gfh#bp w9)Hk2D2gG5Puc5VS`5(bqGtclUJP67MQK}U3^8f-{87DuloY7h+}ztj?{bNeTmS$7 delta 399 zcmc)GJ4ysW6a`SKyBT{5{D6q4fo;%&iM)FCeIOmFk<2g)FzEVpB)WtNTtY2C&CDE_ z&|SC?Gjm%5x8RNL%?|fz_iJZ$%4*P{(4ffY?BH*#=j@r4NR+pVqr6#e7hRW6CT*UT zANjGG)!1A<@C9Gww_2Czx1gX9XM@@IY4Q zC?tRkOhVdm5P{6ZJ!4PglBVc=7&Uv7Y_b3elLQk5H8~)RWGIWt5<&#-5l31IqHv~2 ZIt^vF{pZ4Ld?@uiKQ2tub^Fty`2x}ISx*1} delta 330 zcmc(ZF>V4e5CCOD1iGtJbqS(LD TQlqru`ShO&o8Ex;@9pO=_@Y>P delta 319 zcmc)EA#MXP5QSl_6jh8A@cTY}y{tKUNV#!r<{Gx=aIcmcK`NMr T4dO*hv;7jZV&Bd{Wra%mpOZ8c6T^iCx=Hp$!)Op=U>175f~;|F?<_5eAs{D zrWf@aCe`k4RhKTE1n+|W(L}PtB6tx5ZaQkkc%vcVeCRkv2>1yZH47<#@6(%i!ac!&Db; zcb6a$5Q!1(8mOUaRrsC3HXRh2H58O@t8#^dU#}Y2N=$$>=J30H|`GCFN-a9^d!rr^Gg2LB3 z>{lg(=#fgccU69@96K(H>nrx`r=2<0XpVJ1t=thfdeHnCA9|y@hvFl#@nR>jE>+Ba;f&qXNFevPrPTs`nSHEQ%U#*)%s#v~BWI z()uabN@~*qPGpfgN=7CC=p`RbNJ?4-!(a2Rm?S_X*4RYtYse&d97zq6o?g60Og1~^ zXkwZ4Iv|ai^v;jhgvrmLYhj=Jc!wy1|Z1nR`{q^Sw4EQz>H(5844vMi8^;gLdJ(iGHJgiLApzhv-n zZm0&KL|-MsrZwaVhKPg<%&Rp=MS9&z6C(6fF+phyAX1h`5$X|-p&YfCT0>59B&On)?6byHaFX(3=Gcq&frDcyXeWa< zr59OY!Eq0(^)D+W`lBB?qVOl8uioyQp4Z+y(QCt&da({)*JJKNXiR7cV62sZzt2i9 zCs<#EPc;|QdVC#sx`V*P3RnsF;LLE-dD%34F+jZuV8_AlhrnJAFFbBTVfy^Z2E?s!oq_`{7cag)Y>05>W5<0&Rv~ z24`y#`}pirkfZqDfjr~34YTgV`X}DSa3G9arwI# zTKIHnzC+fpX6BAxA43bDxZfCBcZ&J%uy4Bzr)qZBE?dY8eej&lx+K(!mzd=9Z}N3<(|`H)zA0T!p+FK)IMe)C zWQ;Z}XSXs%i8T7L=}cxQAGRb@277QxCM-VWmt~Y}TatxH87<39gz$E$pGDSaNv5S< z(V;bE{JLXx7_Z>d)~?7xfy~y@*if&oEsT)gTJD$V6`4_Vzjd*g5DB-LtS-~>r7J1v z|M-x-dT6xE6D3kNbSg{jFiAv|hPlp7?uN0;GGxRZBtlu8r6wIZF&e7SL@v&Z8OAmj zLu+#zrz0zMo+p_dg(l8aHq@!I7@|iyHL)7yk-|_D8yvkp|!L>HQvM_j}#!eo)nES$o$u*2KZq)}!Y~!QYz|^8o+= delta 409 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 Y?%wX+q^eV2ucgDZp`_D!dUito1%q^9ZU6uP literal 0 HcmV?d00001 diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/cmp_markerInPolylineElement.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/cmp_markerInPolylineElement.pdf index 5af408419faa5fc99a01a325d17a5d005d9041b7..27c0fee178da2bb3008dbd4b673c480a96e61bd6 100644 GIT binary patch delta 702 zcmc&xy>1gh5Z2+t2}^|#AVr9*6qy)BoM&eL5m1GQ0t8f4NSycf5>V`bOJ(S}OL|C`fq$wwV1i-_AGR&iuac_0mUP3`u}S5ON2^Ho*3c(Zi!= zx1NXL?kxh6NPizJ?-$>So(2`K^zN*U_9lWOE+6-{inBzDoA|xAam_hlEx!pBB1pmi z-I<6V%FQUtt@xun7oV4J3$grJUN5dzkdETOO_hWy^=$MYO!wyp9JPwWJ}pi^;IqJ< zvMGDbAXOos?Xv+7hlej-9S7Elh{`BF$xv06cn&8-2Ry?{+uRXWG_0z8(#%v2Iq5oY zo@J4h$&=dL$g`F`VJu9W&(S?x&N-9_^JPSN2Nh^e+53}ECWCT zX-=nd&SHGCwy_`?LQ95}aKX*;UXX&0{6jU%CjwCGS;Ko82+-k}=HdQ8@Zpv@xOz5PEel*vPg@7Fie S_`a+U&l4)e27`N#_ShewUZ{Qvjw>26V@RZPSK7)Wn-|4@?!G1^0PU|{M2 zgh@TYB6uG`a1`%gMFmw9k6Q11Zok$=0~(lG$1fZ4&()qR}%WoqWf1jI;xh3>L= zFG|*s$K`2vTTY6+JABMvgHiW9+%NLS#!G>Dx%oC$+STx*`mU~i4WL#g-;DNFtW_(~ zbMish1WaO5^hjta5GQN3<%R1bzfb`qLqL!ets&o{_3S{zNgzi;P6b0^h>do>4PK{Y xBpIbeS@h&}iLW5XMr{~uf)i=>7Y%u@; diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/cmp_markerShorthandInPolyline.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/cmp_markerShorthandInPolyline.pdf new file mode 100644 index 0000000000000000000000000000000000000000..fb33376d9739aa8bf92f973e47785f4d4181e6ad GIT binary patch literal 2484 zcmd5;-EP}96u#$EoExJF221=AMX3l3q;``PYa7=Nx&dh}^h3EWY$=uGF4-IHX0Nh~ zy}|Y(J4cf3*m2VW9k9xuqZ8rj&OK?`ucP{{qf=w-W{Euk6*$kTUHqG-7)+wIp=)}38y#Z zU1j0CELJ!0`t9)+D^b-=Y*?(2JK_E`Ppd0pesb+@sHnDGh`p}Mvj^ODE3AF@^Yj}U zyP&m7?fApg%a%kW9xu&p1-!G!yW^5Hw$UD4=!G zn!g#CS_3ac1n`9H_s%x^I^6q%{nzN5oxB785b*Dc@Y~X6xF$j{ zBD#IR*IH@FU~QAM?dgGhWAh}cYtJS%CiXoWH+T;0+b{*~+dPA7zvt)sc(&}?gu)cQ zZ_^L42qW&{tIKGk7}X&OiTt{+nswkWb&UlN0}?&F1Ah z5VGGdN@wF0`@sCOm4IQ+-Y{mfv@v6ix&&?4L7tU1D+{3E#{MgtF5>6;?G?x0kaGw$ zzxGG5Lm!Zp%h(qA+9kHYz`tKi-`k|b8bu4Ky^oK7=@zR8qg>wISR86@`+b5$Km_(^ z=0FWa6Qc4Q#AUq9=dH79od-C{a*=1lxU@&ZA0?N8kTQ@$3MGEv>KW(Hj{R48`nbc$ z<>@-H?r3poZ_7_G$eo3rCp_MrygnUGe!jSbw@0VvqnGf}x&i~fJ%+y|=e$cH;q=Dc z6&B82zP^FizaF<(iK=E|gM5wL3ICTxT3iwH<7tya}6`Ww_IeFiBN;kuwqhbFdCLj zq0G^;WRs>F2RGkR(D)+@+#?0z+mw~ba3hc>uP(cr%CXP~kWLt=Cgg1PDn89$@>ntQ!c?lc32uy&QzraQY=^CgPDHXrT;HK%1gA zKN*{4O)TsM%#eDYl4Mm`vVOkB=>x>#iIp|u3arv&2=8BPb zwf;*q&<_dl5MtUDJBU3@K%DY*6R^d-v(3H@_x@nt8-2Btci?{~;O#IiWLyPLbJ43# zq9@XR>+B3yMhHf9*AIkRD-AQ)*d%R!dLY}{0*M;ivq_DR_H5kXX|Qj@M6_=U3@TvH zFAVX7*|iCUiG1ItA7T+k+{0J8c(JsOZV@kraCM@Rgqui(X&eczBg+$`Wh^2SO38IR z6H%hlluo~Chz@BQ3q6atNz7D*!iK4`aS$rYdokLiv5{3t5QsG5TFz!7m9tb>A;M{j zVMGub9;9(1umH+?% literal 0 HcmV?d00001 diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/cmp_markerShorthandTagInheritance.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/cmp_markerShorthandTagInheritance.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ad8598158e96893938d4eb8055a5f983d48972b2 GIT binary patch literal 2490 zcmc&$-EP}96u#$EoExJF21|z&f21KWklIUDtZiI7*aoDz&=2jpu&q>*yJT;)o4!gf z_6FOF>`;>J*m2VWDKHrpsl!8_j~_oCvNIfa^kL9%|+9$y+@CKSM!CGZu{6}w_IeJI1H!3C zI|tWLwjpZIeq6=#e7bcGw$6Q;WHrl|gSfIsgC7M7$p!tTl1lu5!862X$NsB4d)#4I z2<#nJ52-d3NWpBEM)k9*i1zdjv~f4;bcw@0Vv!U79|CIdklXGMC`hdaC%eR zl@`v6e02k_e?8t}byT$z>*p)tj{CpNvhvC?Kf3leRFvB;j=i?a^9S6uE3CBtW%`X9 zyQY7^x=p{=(>Vd7}5pnK>2YBMV?nAo~F5ZQ`=)&a#6nuJBS{^ z9nuIR3LzkBYXNWv?^`ExPpeQ^_8VK$6r7R6=$vWzgC=*A&+q25rDa?z;0hK@2n9yL zoCPFvvdr1I?S@cHHx#t~!~%Lwf%I$3+GNmh;>l~u?z*xm$)Eh(6cL&?eXi;41|A`3 z-ei7+_cw>2wKJ%39Do)@K^Ou-;v6NlZ_1{@A$k%t(WIAy&{|Hv1kHpP8V5}aNdj6I zjrqyIf;F&1xz8=azFv(-Qt;IEI+2>-zFaAveSJeY(Csi=4L0jc8YDTWMuu_qu9oJ4 zIq!P?=VWjnPJo9HyIrw^*rNo5E?>6+x43t<*|*`|AMAUhuXpke{O<&OJIod`t%9eJ zNA*ecMA~l)JE4`~oH@Fi2eeXwf(fi`!fk%{z;a`gf;6^g6N(`1+0f8wuy3P8v~QD! z6tL%~HJvcKHXcwS-?yoUSh(T$@Kr@To7=+OB3=yO>O?12TOOwwml&fGXpM<6(^-@V zZ8DwOWD<%HQOa1VERsTFtc0AzMjMRv1UaTzq(UjJQQC^Y26ke?Buo>unGDldP7;lY zOhh6uq2^4cBC?STQf*}K|3`4`zgSLka2a*vkLW<8bHr80vp+4#fllmBeP8Ih>q2+; Wy1>dRE~;8OJi>r=IzL^UvHt)UDR$@p literal 0 HcmV?d00001 diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/cmp_markerShorthandWithFillAndStroke.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/cmp_markerShorthandWithFillAndStroke.pdf new file mode 100644 index 0000000000000000000000000000000000000000..479dfd6298d59ba04f5efb356cd4e9e85ad2b6ee GIT binary patch literal 6674 zcmeI1&2HO95P~bl|lB}3PfLwVAIQ;B|COHK zmG6P^!JsH}9nHu`(jU$koMq%KA$p!VF}BPUxte;K%}YHm3oz+Oslq$*DcT~Kf^u=NS zb(ZcQaG7W6BGLK5;=fwNrGY)n@>yle-Kb@J81NLj=7e_`k{Rhh@#zloEGsd1s_yEDefwg` zSpAaQOfa^`@c>nfj13B5-DH5joR|YMu9zX%tfFu@6TnPF7^wti!D3SZt0H+g^MKii zM5zzV(!pi`thN^dv-Y0JZ0(VNT$5kO97!1=h5XJnM(2d~d>}}?etUcPH(86l0QSH%)&>HLWYJDqaJ5gD09W2|nxLoV% zDPXq088W|i=qY4hp)=T{6QO;D#<13Cu$fq4_DSq1%0hhfH_k|u^)P)rdN$Fp1BtVFD*)5(3Ii7=Vjrqo&07Cjn(JJelvP=a?@a_mB> z&F6NIZQ1!rmF4XqdsubZR)YFbwVR4cR_fgRlbwZ`S&mv_7W*@a*(#w$)(DwNH7&A6 z$kyulWpUo7GEasp%edJ+G#{8RWs+lj zZpgU8%(x+=KCa1|GPCGx$fS=qZ$svJST#PDagG(!rc8+~|9BuU?fEQ@ zIE#d&aVk6+GZEp2d>F7W4w5vLA@zAQmNb>ZqaIgm@c(;o+kZJ9XHacgk8q + + + + + + + + + + + + + + + + path with arc segments + + \ No newline at end of file diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerInPolygonElementWithComplexAngle.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerInPolygonElementWithComplexAngle.svg new file mode 100644 index 0000000000..f5221e5772 --- /dev/null +++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerInPolygonElementWithComplexAngle.svg @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerRefXY.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerRefXY.svg index 08e6acb6a3..c8e08fbb0a 100644 --- a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerRefXY.svg +++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerRefXY.svg @@ -80,30 +80,30 @@ refX,Y (0,-5) - refX,Y (0em,2em) + refX,Y (0em,2em) - refX,Y (0px,5px) + refX,Y (0px,5px) - refX,Y (0pt,5pt) ) + refX,Y (0pt,5pt) ) - refX,Y (0mm,5mm) + refX,Y (0mm,5mm) - refX,Y (0ex,5ex) + refX,Y (0ex,5ex) - refX,Y (0cm,0.5cm) + refX,Y (0cm,0.5cm) - refX,Y (0pc,2pc) + refX,Y (0pc,2pc) - refX,Y (0%,5%) + refX,Y (0%,5%) - refX,Y (0in,0.1in) + refX,Y (0in,0.1in) \ No newline at end of file diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerShorthandInPolyline.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerShorthandInPolyline.svg new file mode 100644 index 0000000000..0410ea29a4 --- /dev/null +++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerShorthandInPolyline.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerShorthandInheritance.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerShorthandInheritance.svg new file mode 100644 index 0000000000..76bbb97e34 --- /dev/null +++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerShorthandInheritance.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerShorthandTagInheritance.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerShorthandTagInheritance.svg new file mode 100644 index 0000000000..5dfd45e4b4 --- /dev/null +++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerShorthandTagInheritance.svg @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerShorthandWithFillAndStroke.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerShorthandWithFillAndStroke.svg new file mode 100644 index 0000000000..437328b749 --- /dev/null +++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/markerShorthandWithFillAndStroke.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/parentStrokeWidthIsMetricValues.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/parentStrokeWidthIsMetricValues.svg index 535831a3bf..7dbe71cfd2 100644 --- a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/parentStrokeWidthIsMetricValues.svg +++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/MarkerSvgNodeRendererIntegrationTest/parentStrokeWidthIsMetricValues.svg @@ -12,14 +12,14 @@ stroke-width="1pt" - stroke-width="1mm" + stroke-width="1mm" - stroke-width="1cm" + stroke-width="1cm" - stroke-width="1pc" + stroke-width="1pc" - stroke-width="0.3in" + stroke-width="0.3in" \ No newline at end of file diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/StrokeTest/strokeWidthMeasureUnitsTest.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/StrokeTest/strokeWidthMeasureUnitsTest.svg index 011df44059..fa83cbe14d 100644 --- a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/StrokeTest/strokeWidthMeasureUnitsTest.svg +++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/StrokeTest/strokeWidthMeasureUnitsTest.svg @@ -17,34 +17,34 @@ Polyline element - stroke-width="1ex" - Polyline element - + stroke-width="1ex" + Polyline element + - stroke-width="1%" - Polyline element + stroke-width="1%" + Polyline element - stroke-width="1ex" - Polygon element + stroke-width="1ex" + Polygon element - stroke-width="1em" - Polygon element + stroke-width="1em" + Polygon element - stroke-width="0.3%" - Polygon element - + stroke-width="0.3%" + Polygon element + - stroke-width="0.3em" - Path element - + stroke-width="0.3em" + Path element + - stroke-width="0.3ex" - Path element - + stroke-width="0.3ex" + Path element + - stroke-width="0.3%" - Path element + stroke-width="0.3%" + Path element \ No newline at end of file diff --git a/itext/itext.kernel/itext/kernel/geom/Point.cs b/itext/itext.kernel/itext/kernel/geom/Point.cs index 0a73eb44bb..68ce904f29 100644 --- a/itext/itext.kernel/itext/kernel/geom/Point.cs +++ b/itext/itext.kernel/itext/kernel/geom/Point.cs @@ -53,6 +53,22 @@ public Point(double x, double y) { SetLocation(x, y); } + /// + /// Instantiates a new + /// + /// instance based on other + /// + /// instance. + /// + /// + /// other + /// + /// instance from which coordinates will be copied + /// + public Point(iText.Kernel.Geom.Point other) { + SetLocation(other.GetX(), other.GetY()); + } + /// Gets x coordinate of the point. /// the x coordinate public virtual double GetX() { diff --git a/itext/itext.styledxmlparser/itext/styledxmlparser/css/CommonCssConstants.cs b/itext/itext.styledxmlparser/itext/styledxmlparser/css/CommonCssConstants.cs index 9ae275d296..5312aed1b0 100644 --- a/itext/itext.styledxmlparser/itext/styledxmlparser/css/CommonCssConstants.cs +++ b/itext/itext.styledxmlparser/itext/styledxmlparser/css/CommonCssConstants.cs @@ -427,6 +427,18 @@ static CommonCssConstants() { /// The Constant MARGIN_TOP. public const String MARGIN_TOP = "margin-top"; + /// The Constant MARKER + public const String MARKER = "marker"; + + /// The Constant MARKER_MID + public const String MARKER_MID = "marker-mid"; + + /// The Constant MARKER_START + public const String MARKER_START = "marker-start"; + + /// The Constant MARKER_END + public const String MARKER_END = "marker-end"; + /// The Constant MIN_HEIGHT. public const String MIN_HEIGHT = "min-height"; diff --git a/itext/itext.styledxmlparser/itext/styledxmlparser/css/resolve/shorthand/ShorthandResolverFactory.cs b/itext/itext.styledxmlparser/itext/styledxmlparser/css/resolve/shorthand/ShorthandResolverFactory.cs index b63a108341..4bba1b00a2 100644 --- a/itext/itext.styledxmlparser/itext/styledxmlparser/css/resolve/shorthand/ShorthandResolverFactory.cs +++ b/itext/itext.styledxmlparser/itext/styledxmlparser/css/resolve/shorthand/ShorthandResolverFactory.cs @@ -61,6 +61,7 @@ static ShorthandResolverFactory() { shorthandResolvers.Put(CommonCssConstants.GRID_COLUMN, new GridColumnShorthandResolver()); shorthandResolvers.Put(CommonCssConstants.GRID_TEMPLATE, new GridTemplateShorthandResolver()); shorthandResolvers.Put(CommonCssConstants.GRID, new GridShorthandResolver()); + shorthandResolvers.Put(CommonCssConstants.MARKER, new MarkerShorthandResolver()); } /// Gets a shorthand resolver. diff --git a/itext/itext.styledxmlparser/itext/styledxmlparser/css/resolve/shorthand/impl/MarkerShorthandResolver.cs b/itext/itext.styledxmlparser/itext/styledxmlparser/css/resolve/shorthand/impl/MarkerShorthandResolver.cs new file mode 100644 index 0000000000..0943bf719a --- /dev/null +++ b/itext/itext.styledxmlparser/itext/styledxmlparser/css/resolve/shorthand/impl/MarkerShorthandResolver.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Logging; +using iText.Commons; +using iText.Commons.Utils; +using iText.StyledXmlParser.Css; +using iText.StyledXmlParser.Css.Resolve.Shorthand; +using iText.StyledXmlParser.Css.Util; + +namespace iText.StyledXmlParser.Css.Resolve.Shorthand.Impl { + public class MarkerShorthandResolver : IShorthandResolver { + private static readonly ILogger LOGGER = ITextLogManager.GetLogger(typeof(iText.StyledXmlParser.Css.Resolve.Shorthand.Impl.MarkerShorthandResolver + )); + + /// + /// Creates a new + /// + /// instance. + /// + public MarkerShorthandResolver() { + } + + //empty constructor + public virtual IList ResolveShorthand(String shorthandExpression) { + if (CssTypesValidationUtils.IsInitialOrInheritOrUnset(shorthandExpression)) { + return JavaUtil.ArraysAsList(new CssDeclaration(CommonCssConstants.MARKER_START, shorthandExpression), new + CssDeclaration(CommonCssConstants.MARKER_MID, shorthandExpression), new CssDeclaration(CommonCssConstants + .MARKER_END, shorthandExpression)); + } + String expression = shorthandExpression.Trim(); + if (String.IsNullOrEmpty(expression)) { + LOGGER.LogWarning(MessageFormatUtil.Format(iText.StyledXmlParser.Logs.StyledXmlParserLogMessageConstant.SHORTHAND_PROPERTY_CANNOT_BE_EMPTY + , CommonCssConstants.MARKER)); + return new List(); + } + if (!expression.StartsWith(CommonCssConstants.URL + "(") || !expression.EndsWith(")")) { + LOGGER.LogWarning(MessageFormatUtil.Format(iText.StyledXmlParser.Logs.StyledXmlParserLogMessageConstant.INVALID_CSS_PROPERTY_DECLARATION + , shorthandExpression)); + return new List(); + } + return JavaUtil.ArraysAsList(new CssDeclaration(CommonCssConstants.MARKER_START, shorthandExpression), new + CssDeclaration(CommonCssConstants.MARKER_MID, shorthandExpression), new CssDeclaration(CommonCssConstants + .MARKER_END, shorthandExpression)); + } + } +} diff --git a/itext/itext.svg/itext/svg/SvgConstants.cs b/itext/itext.svg/itext/svg/SvgConstants.cs index 3f4ec00eab..455f75b9e1 100644 --- a/itext/itext.svg/itext/svg/SvgConstants.cs +++ b/itext/itext.svg/itext/svg/SvgConstants.cs @@ -404,6 +404,9 @@ public sealed class Attributes : CommonAttributeConstants { /// Attribute defining the height of the viewport in which the marker is to be fitted public const String MARKER_HEIGHT = "markerHeight"; + /// Attribute defining shorthand for marker-start/marker-mid/marker-end + public const String MARKER = "marker"; + /// Attribute defining the marker drawn at every other vertex but the start and end of a path, line, polygon or polyline /// public const String MARKER_MID = "marker-mid"; diff --git a/itext/itext.svg/itext/svg/css/impl/SvgStyleResolver.cs b/itext/itext.svg/itext/svg/css/impl/SvgStyleResolver.cs index c31499d46f..94e12007a9 100644 --- a/itext/itext.svg/itext/svg/css/impl/SvgStyleResolver.cs +++ b/itext/itext.svg/itext/svg/css/impl/SvgStyleResolver.cs @@ -420,12 +420,9 @@ private void ProcessAttribute(IAttribute attr, IDictionary style } private IDictionary ParseStylesFromStyleAttribute(String style) { - IDictionary parsed = new Dictionary(); - IList declarations = CssRuleSetParser.ParsePropertyDeclarations(style); - foreach (CssDeclaration declaration in declarations) { - parsed.Put(declaration.GetProperty(), declaration.GetExpression()); - } - return parsed; + IList ruleSets = JavaCollectionsUtil.SingletonList(new CssRuleSet(null, CssRuleSetParser.ParsePropertyDeclarations + (style))); + return CssStyleSheet.ExtractStylesFromRuleSets(ruleSets); } } } diff --git a/itext/itext.svg/itext/svg/renderers/impl/AbstractSvgNodeRenderer.cs b/itext/itext.svg/itext/svg/renderers/impl/AbstractSvgNodeRenderer.cs index af40379049..0cd945af58 100644 --- a/itext/itext.svg/itext/svg/renderers/impl/AbstractSvgNodeRenderer.cs +++ b/itext/itext.svg/itext/svg/renderers/impl/AbstractSvgNodeRenderer.cs @@ -43,9 +43,8 @@ namespace iText.Svg.Renderers.Impl { /// abstract implementation. /// public abstract class AbstractSvgNodeRenderer : ISvgNodeRenderer { - // TODO (DEVSIX-3397) Add MarkerVertexType.MARKER_MID after ticket will be finished. private static readonly MarkerVertexType[] MARKER_VERTEX_TYPES = new MarkerVertexType[] { MarkerVertexType - .MARKER_START, MarkerVertexType.MARKER_END }; + .MARKER_START, MarkerVertexType.MARKER_MID, MarkerVertexType.MARKER_END }; /// Map that contains attributes and styles used for drawing operations. protected internal IDictionary attributesAndStyles; @@ -318,12 +317,9 @@ internal virtual void PostDraw(SvgDrawContext context) { } // Marker drawing if (this is IMarkerCapable) { - // TODO (DEVSIX-3397) add processing of 'marker' property (shorthand for a joint using of all other properties) foreach (MarkerVertexType markerVertexType in MARKER_VERTEX_TYPES) { if (attributesAndStyles.ContainsKey(markerVertexType.ToString())) { - currentCanvas.SaveState(); ((IMarkerCapable)this).DrawMarker(context, markerVertexType); - currentCanvas.RestoreState(); } } } diff --git a/itext/itext.svg/itext/svg/renderers/impl/MarkerSvgNodeRenderer.cs b/itext/itext.svg/itext/svg/renderers/impl/MarkerSvgNodeRenderer.cs index 2002b09468..c9a43029fd 100644 --- a/itext/itext.svg/itext/svg/renderers/impl/MarkerSvgNodeRenderer.cs +++ b/itext/itext.svg/itext/svg/renderers/impl/MarkerSvgNodeRenderer.cs @@ -21,8 +21,10 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ using System; +using System.Collections.Generic; using Microsoft.Extensions.Logging; using iText.Commons; +using iText.Commons.Utils; using iText.Kernel.Geom; using iText.StyledXmlParser.Css.Util; using iText.Svg; @@ -36,6 +38,13 @@ namespace iText.Svg.Renderers.Impl { /// implementation for the <marker> tag. /// public class MarkerSvgNodeRenderer : AbstractBranchSvgNodeRenderer { + /// Attribute defining the marker index on polygon, line or polyline. + /// + /// Attribute defining the marker index on polygon, line or polyline. + /// It is not a property from css standard, used for internal marker processing. + /// + public const String MARKER_INDEX = "marker-index"; + // Default marker width in point units (3 px) private const float DEFAULT_MARKER_WIDTH = 2.25f; @@ -98,13 +107,41 @@ internal static void DrawMarker(SvgDrawContext context, String moveX, String mov namedObject.SetAttribute(SvgConstants.Tags.MARKER, markerToUse.ToString()); namedObject.SetAttribute(SvgConstants.Attributes.X, moveX); namedObject.SetAttribute(SvgConstants.Attributes.Y, moveY); + context.GetCurrentCanvas().SaveState(); namedObject.Draw(context); + context.GetCurrentCanvas().RestoreState(); // unsetting the parent of the referenced element namedObject.SetParent(null); } } //\endcond +//\cond DO_NOT_DOCUMENT + internal static void DrawMarkers(SvgDrawContext context, int startIndex, IList markerPoints, MarkerVertexType + markerToUse, AbstractSvgNodeRenderer parent) { + String elementToReUse = SvgTextUtil.FilterReferenceValue(parent.attributesAndStyles.Get(markerToUse.ToString + ())); + ISvgNodeRenderer template = context.GetNamedObject(elementToReUse); + if (!(template is MarkerSvgNodeRenderer && + // Having markerWidth or markerHeight with negative or zero value disables rendering of the element . + MarkerWidthHeightAreCorrect((MarkerSvgNodeRenderer)template))) { + return; + } + for (int i = 0; i < markerPoints.Count; ++i) { + ISvgNodeRenderer marker = template.CreateDeepCopy(); + // setting the parent of the referenced element to this instance + marker.SetParent(parent); + marker.SetAttribute(SvgConstants.Tags.MARKER, markerToUse.ToString()); + marker.SetAttribute(SvgConstants.Attributes.X, SvgCssUtils.ConvertDoubleToString(markerPoints[i].GetX())); + marker.SetAttribute(SvgConstants.Attributes.Y, SvgCssUtils.ConvertDoubleToString(markerPoints[i].GetY())); + marker.SetAttribute(MarkerSvgNodeRenderer.MARKER_INDEX, JavaUtil.IntegerToString(startIndex + i)); + context.GetCurrentCanvas().SaveState(); + marker.Draw(context); + context.GetCurrentCanvas().RestoreState(); + } + } +//\endcond + //\cond DO_NOT_DOCUMENT internal override void ApplyViewBox(SvgDrawContext context) { if (this.attributesAndStyles != null) { diff --git a/itext/itext.svg/itext/svg/renderers/impl/PathSvgNodeRenderer.cs b/itext/itext.svg/itext/svg/renderers/impl/PathSvgNodeRenderer.cs index 6d180539b7..4084f77501 100644 --- a/itext/itext.svg/itext/svg/renderers/impl/PathSvgNodeRenderer.cs +++ b/itext/itext.svg/itext/svg/renderers/impl/PathSvgNodeRenderer.cs @@ -420,48 +420,46 @@ private static bool EndsWithNonWhitespace(StringBuilder sb) { public virtual void DrawMarker(SvgDrawContext context, MarkerVertexType markerVertexType) { Object[] allShapesOrdered = GetShapes().ToArray(); - Point point = null; + IList markerPoints = new List(); + int startingPoint = 0; if (MarkerVertexType.MARKER_START.Equals(markerVertexType)) { - point = ((AbstractPathShape)allShapesOrdered[0]).GetEndingPoint(); + markerPoints.Add(new Point(((AbstractPathShape)allShapesOrdered[0]).GetEndingPoint())); } else { if (MarkerVertexType.MARKER_END.Equals(markerVertexType)) { - point = ((AbstractPathShape)allShapesOrdered[allShapesOrdered.Length - 1]).GetEndingPoint(); + markerPoints.Add(new Point(((AbstractPathShape)allShapesOrdered[allShapesOrdered.Length - 1]).GetEndingPoint + ())); + startingPoint = allShapesOrdered.Length - 2; + } + else { + if (MarkerVertexType.MARKER_MID.Equals(markerVertexType)) { + for (int i = 1; i < allShapesOrdered.Length - 1; ++i) { + markerPoints.Add(new Point(((AbstractPathShape)allShapesOrdered[i]).GetEndingPoint())); + } + startingPoint = 1; + } } } - if (point != null) { - String moveX = SvgCssUtils.ConvertDoubleToString(point.GetX()); - String moveY = SvgCssUtils.ConvertDoubleToString(point.GetY()); - MarkerSvgNodeRenderer.DrawMarker(context, moveX, moveY, markerVertexType, this); + if (!markerPoints.IsEmpty()) { + MarkerSvgNodeRenderer.DrawMarkers(context, startingPoint, markerPoints, markerVertexType, this); } } public virtual double GetAutoOrientAngle(MarkerSvgNodeRenderer marker, bool reverse) { Object[] pathShapes = GetShapes().ToArray(); - if (pathShapes.Length > 1) { - Vector v = new Vector(0, 0, 0); - if (SvgConstants.Attributes.MARKER_END.Equals(marker.attributesAndStyles.Get(SvgConstants.Tags.MARKER))) { - // Create vector from the last two shapes - IPathShape lastShape = (IPathShape)pathShapes[pathShapes.Length - 1]; - IPathShape secondToLastShape = (IPathShape)pathShapes[pathShapes.Length - 2]; - v = new Vector((float)(lastShape.GetEndingPoint().GetX() - secondToLastShape.GetEndingPoint().GetX()), (float - )(lastShape.GetEndingPoint().GetY() - secondToLastShape.GetEndingPoint().GetY()), 0f); - } - else { - if (SvgConstants.Attributes.MARKER_START.Equals(marker.attributesAndStyles.Get(SvgConstants.Tags.MARKER))) { - // Create vector from the first two shapes - IPathShape firstShape = (IPathShape)pathShapes[0]; - IPathShape secondShape = (IPathShape)pathShapes[1]; - v = new Vector((float)(secondShape.GetEndingPoint().GetX() - firstShape.GetEndingPoint().GetX()), (float)( - secondShape.GetEndingPoint().GetY() - firstShape.GetEndingPoint().GetY()), 0f); - } - } - // Get angle from this vector and the horizontal axis + int markerIndex = Convert.ToInt32(marker.GetAttribute(MarkerSvgNodeRenderer.MARKER_INDEX), System.Globalization.CultureInfo.InvariantCulture + ); + if (markerIndex < pathShapes.Length && pathShapes.Length > 1) { + Vector v; + IPathShape firstShape = (IPathShape)pathShapes[markerIndex]; + IPathShape secondShape = (IPathShape)pathShapes[markerIndex + 1]; + v = new Vector((float)(secondShape.GetEndingPoint().GetX() - firstShape.GetEndingPoint().GetX()), (float)( + secondShape.GetEndingPoint().GetY() - firstShape.GetEndingPoint().GetY()), 0f); Vector xAxis = new Vector(1, 0, 0); double rotAngle = SvgCoordinateUtils.CalculateAngleBetweenTwoVectors(xAxis, v); - return v.Get(1) >= 0 && !reverse ? rotAngle : rotAngle * -1f; + return v.Get(1) >= 0 && !reverse ? rotAngle : rotAngle * -1.0; } - return 0; + return 0.0; } private static Point GetCurrentPoint(IPathShape previousShape) { diff --git a/itext/itext.svg/itext/svg/renderers/impl/PolylineSvgNodeRenderer.cs b/itext/itext.svg/itext/svg/renderers/impl/PolylineSvgNodeRenderer.cs index 1b8a6cddde..3a63792572 100644 --- a/itext/itext.svg/itext/svg/renderers/impl/PolylineSvgNodeRenderer.cs +++ b/itext/itext.svg/itext/svg/renderers/impl/PolylineSvgNodeRenderer.cs @@ -36,6 +36,9 @@ namespace iText.Svg.Renderers.Impl { /// implementation for the <polyline> tag. /// public class PolylineSvgNodeRenderer : AbstractSvgNodeRenderer, IMarkerCapable { + /// orientation vector which is used for marker angle calculation. + private Vector previousOrientationVector = new Vector(1, 0, 0); + /// /// A List of /// @@ -133,44 +136,51 @@ public override ISvgNodeRenderer CreateDeepCopy() { } public virtual void DrawMarker(SvgDrawContext context, MarkerVertexType markerVertexType) { - Point point = null; + IList markerPoints = new List(); + int startingPoint = 0; if (MarkerVertexType.MARKER_START.Equals(markerVertexType)) { - point = points[0]; + markerPoints.Add(new Point(points[0])); } else { if (MarkerVertexType.MARKER_END.Equals(markerVertexType)) { - point = points[points.Count - 1]; + markerPoints.Add(new Point(points[points.Count - 1])); + startingPoint = points.Count - 2; } + else { + if (MarkerVertexType.MARKER_MID.Equals(markerVertexType)) { + for (int i = 1; i < points.Count - 1; ++i) { + markerPoints.Add(new Point(points[i])); + } + startingPoint = 1; + } + } + } + foreach (Point point in markerPoints) { + point.SetLocation(CssUtils.ConvertPtsToPx(point.GetX()), CssUtils.ConvertPtsToPx(point.GetY())); } - if (point != null) { - String moveX = SvgCssUtils.ConvertDoubleToString(CssUtils.ConvertPtsToPx(point.GetX())); - String moveY = SvgCssUtils.ConvertDoubleToString(CssUtils.ConvertPtsToPx(point.GetY())); - MarkerSvgNodeRenderer.DrawMarker(context, moveX, moveY, markerVertexType, this); + if (!markerPoints.IsEmpty()) { + MarkerSvgNodeRenderer.DrawMarkers(context, startingPoint, markerPoints, markerVertexType, this); } } public virtual double GetAutoOrientAngle(MarkerSvgNodeRenderer marker, bool reverse) { - if (points.Count > 1) { - Vector v = new Vector(0, 0, 0); - if (SvgConstants.Attributes.MARKER_END.Equals(marker.attributesAndStyles.Get(SvgConstants.Tags.MARKER))) { - Point lastPoint = points[points.Count - 1]; - Point secondToLastPoint = points[points.Count - 2]; - v = new Vector((float)(lastPoint.GetX() - secondToLastPoint.GetX()), (float)(lastPoint.GetY() - secondToLastPoint - .GetY()), 0f); - } - else { - if (SvgConstants.Attributes.MARKER_START.Equals(marker.attributesAndStyles.Get(SvgConstants.Tags.MARKER))) { - Point firstPoint = points[0]; - Point secondPoint = points[1]; - v = new Vector((float)(secondPoint.GetX() - firstPoint.GetX()), (float)(secondPoint.GetY() - firstPoint.GetY - ()), 0f); - } - } - Vector xAxis = new Vector(1, 0, 0); + int markerIndex = Convert.ToInt32(marker.GetAttribute(MarkerSvgNodeRenderer.MARKER_INDEX), System.Globalization.CultureInfo.InvariantCulture + ); + if (markerIndex < points.Count && points.Count > 1) { + Vector v; + Point firstPoint = points[markerIndex]; + Point secondPoint = points[markerIndex + 1]; + v = new Vector((float)(secondPoint.GetX() - firstPoint.GetX()), (float)(secondPoint.GetY() - firstPoint.GetY + ()), 0f); + Vector xAxis = SvgConstants.Attributes.MARKER_END.Equals(marker.attributesAndStyles.Get(SvgConstants.Tags. + MARKER)) || SvgConstants.Attributes.MARKER_START.Equals(marker.attributesAndStyles.Get(SvgConstants.Tags + .MARKER)) ? new Vector(1, 0, 0) : new Vector(previousOrientationVector.Get(1), previousOrientationVector + .Get(0) * -1.0F, 0.0F); + previousOrientationVector = v; double rotAngle = SvgCoordinateUtils.CalculateAngleBetweenTwoVectors(xAxis, v); - return v.Get(1) >= 0 && !reverse ? rotAngle : rotAngle * -1f; + return v.Get(1) >= 0 && !reverse ? rotAngle : rotAngle * -1.0; } - return 0; + return 0.0; } } } diff --git a/port-hash b/port-hash index 30d5d2db91..917c69e3f0 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -4cd6065d57c660f788a331f31b96ffbdeea6a13a +7c26497242ba52d98e1843313cf4e7d83d45feb2 From 08947ac2aa60ec801f60c40fb6356fbeef13c8a0 Mon Sep 17 00:00:00 2001 From: iText Software Date: Fri, 27 Dec 2024 10:13:21 +0000 Subject: [PATCH 2/2] Add missing copyright headers Autoported commit. Original commit hash: [6391ccd1d] --- .../shorthand/MarkerShorthandResolverTest.cs | 22 +++++++++++++++++++ .../shorthand/impl/MarkerShorthandResolver.cs | 22 +++++++++++++++++++ port-hash | 2 +- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/itext.tests/itext.styledxmlparser.tests/itext/styledxmlparser/css/resolve/shorthand/MarkerShorthandResolverTest.cs b/itext.tests/itext.styledxmlparser.tests/itext/styledxmlparser/css/resolve/shorthand/MarkerShorthandResolverTest.cs index 7926e59bea..7d1f12c371 100644 --- a/itext.tests/itext.styledxmlparser.tests/itext/styledxmlparser/css/resolve/shorthand/MarkerShorthandResolverTest.cs +++ b/itext.tests/itext.styledxmlparser.tests/itext/styledxmlparser/css/resolve/shorthand/MarkerShorthandResolverTest.cs @@ -1,3 +1,25 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2024 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 System.Collections.Generic; using iText.Commons.Utils; diff --git a/itext/itext.styledxmlparser/itext/styledxmlparser/css/resolve/shorthand/impl/MarkerShorthandResolver.cs b/itext/itext.styledxmlparser/itext/styledxmlparser/css/resolve/shorthand/impl/MarkerShorthandResolver.cs index 0943bf719a..67c3a21811 100644 --- a/itext/itext.styledxmlparser/itext/styledxmlparser/css/resolve/shorthand/impl/MarkerShorthandResolver.cs +++ b/itext/itext.styledxmlparser/itext/styledxmlparser/css/resolve/shorthand/impl/MarkerShorthandResolver.cs @@ -1,3 +1,25 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2024 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 System.Collections.Generic; using Microsoft.Extensions.Logging; diff --git a/port-hash b/port-hash index 917c69e3f0..9a5e30e880 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -7c26497242ba52d98e1843313cf4e7d83d45feb2 +6391ccd1d7647bf14f8ccbf93b7eef9c4dbac5e3