From be1bc7704ec7f78c3d016149ea4ca3e0f30349b7 Mon Sep 17 00:00:00 2001 From: Angelina Pavlovets Date: Mon, 20 Jan 2025 09:18:46 +0000 Subject: [PATCH] Support stroke dash pattern in layout for text elements and underline DEVSIX-8776 Autoported commit. Original commit hash: [0bedf083f] --- .../itext/kernel/pdf/canvas/PdfCanvasTest.cs | 21 +++++++ .../pdf/canvas/PdfCanvasTest/cmp_lineDash.pdf | Bin 0 -> 1197 bytes .../itext/layout/TextWritingTest.cs | 14 +++-- .../TextWritingTest/cmp_strokedUnderline.pdf | Bin 1978 -> 2000 bytes .../cmp_textRenderingModeTest01.pdf | Bin 1017 -> 1269 bytes .../itext/svg/renderers/StrokeTest.cs | 1 - .../impl/TSpanNodeRendererIntegrationTest.cs | 5 ++ .../TextSvgBranchRendererIntegrationTest.cs | 2 - .../impl/StrokeTest/cmp_strokeWithDashes.pdf | Bin 2655 -> 2695 bytes .../impl/StrokeTest/strokeWithDashes.svg | 4 +- .../cmp_textDecorationDashedStroke.pdf | Bin 0 -> 2703 bytes .../textDecorationDashedStroke.svg | 24 ++++++++ .../cmp_textComplexStrokeDasharray.pdf | Bin 1616 -> 1716 bytes .../cmp_textStrokeDasharray.pdf | Bin 1586 -> 2137 bytes .../textComplexStrokeDasharray.svg | 6 +- .../textStrokeDasharray.svg | 26 ++++++-- .../itext/kernel/pdf/canvas/PdfCanvas.cs | 34 +++++++++-- .../itext/layout/ElementPropertyContainer.cs | 32 ++++++++++ .../itext/layout/properties/Property.cs | 16 ++++- .../itext/layout/properties/Underline.cs | 57 ++++++++++++++++++ .../itext/layout/renderer/TextRenderer.cs | 13 ++++ .../renderers/impl/TextLeafSvgNodeRenderer.cs | 2 +- .../itext/svg/utils/SvgTextProperties.cs | 52 ++++++++-------- .../itext.svg/itext/svg/utils/SvgTextUtil.cs | 6 +- port-hash | 2 +- 25 files changed, 267 insertions(+), 50 deletions(-) create mode 100644 itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/canvas/PdfCanvasTest/cmp_lineDash.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/TSpanNodeRendererIntegrationTest/cmp_textDecorationDashedStroke.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/TSpanNodeRendererIntegrationTest/textDecorationDashedStroke.svg diff --git a/itext.tests/itext.kernel.tests/itext/kernel/pdf/canvas/PdfCanvasTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/pdf/canvas/PdfCanvasTest.cs index 335181d92b..b545c5582c 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/pdf/canvas/PdfCanvasTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/pdf/canvas/PdfCanvasTest.cs @@ -1295,6 +1295,27 @@ public virtual void GlyphlineActualTextTest() { } } + [NUnit.Framework.Test] + public virtual void LineDashTest() { + String outPdf = DESTINATION_FOLDER + "lineDash.pdf"; + String cmpPdf = SOURCE_FOLDER + "cmp_lineDash.pdf"; + using (PdfDocument pdfDocument = new PdfDocument(CompareTool.CreateTestPdfWriter(outPdf))) { + PdfCanvas canvas = new PdfCanvas(pdfDocument.AddNewPage()); + canvas.SaveState().SetTextRenderingMode(PdfCanvasConstants.TextRenderingMode.FILL_STROKE).SetStrokeColor(ColorConstants + .BLUE).SetLineWidth(2).SetFontAndSize(PdfFontFactory.CreateFont(StandardFonts.HELVETICA), 30); + canvas.SetLineDash(3); + canvas.BeginText().MoveText(180, 250).ShowText("phase 3").EndText(); + canvas.SetLineDash(new float[] { 0, 0, 0 }, 2); + canvas.BeginText().MoveText(180, 350).ShowText("dashArray [0, 0, 0]").EndText(); + canvas.SetLineDash(new float[] { 5, -5 }, 1); + canvas.BeginText().MoveText(180, 450).ShowText("dashArray [5, -5]").EndText(); + canvas.SetLineDash(5, -10); + canvas.BeginText().MoveText(180, 550).ShowText("phase -10").EndText().RestoreState(); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(outPdf, cmpPdf, DESTINATION_FOLDER, "diff_" + )); + } + private void CreateStandardDocument(PdfWriter writer, int pageCount, PdfCanvasTest.ContentProvider contentProvider ) { PdfDocument pdfDoc = new PdfDocument(writer); diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/canvas/PdfCanvasTest/cmp_lineDash.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/canvas/PdfCanvasTest/cmp_lineDash.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ccfbadfa98ec7f6299f2c641bde3ef5ca41f8466 GIT binary patch literal 1197 zcmc&zO;6N77&azG(%@~;$Z0riV8x}=na*@;$R_*20?Nm-yU{3c=(ba+EG7`!-oFmeSgg zp(GE#ef+Et06|c{s|*jTC9e@Nu9g~B#EQ%g9Hve%e<4}~8baA@7;$DTE3K`;@2Jw1 zIz(kyhP5t!{>O*6KfiYOY+gv@Kke_>J)1q1{jL0dce*>VIkEmQHP?IY^2Wig^8QKR z?YX@^IBq|8uGjB9vS()M&+>29AD`_y*tw#=t1Z5Gy1k@SFE01K++JFI@ajwA;LdiU zW`Rp*@awA^3iF+|2(go*^^W*L;781lLLe_xQ74(>S^1zf3&kff3CQSZUM*W(Z~%%a z6&40fZnIEcT|~>52BUElm}rueatLak<|zm zI%M1-7lfUW7x+bC_dxL)f`~v(qYz`H>w^&YL)f2ECj;l-gfb7Drp@?(S7WVc4-^8< zfH|ZM!E|*hSFVmt*TCFBZnQiBRv8aP!MPOJMG(TYED3Ted@W>Pln2cfFm*H4(JHNI zUo3BhOnRh_vBoNkJlj%7d@&)Ozo6do{G1|`gT#hI%>U?@U%djU!aCcp)MFpLclp8@{}qq-<2*D(xdPGbm) z;wN}e6QgtjBjgw_;+EH7T>d)aMKC*TVCslO4l;BLQOv00y3Em`i=jv8xn*av3E^m8JK9)HEe7$B6MUln;Iyi+sLHU%owh2AnKYV zV=@7_%+3CP1@r2-?*>3lc}1-Rf#_|#t$OzvFhoC-@sy_Jkf#40QYDNm9>tBOCRUQk Ik?E513kwWZrvLx| literal 0 HcmV?d00001 diff --git a/itext.tests/itext.layout.tests/itext/layout/TextWritingTest.cs b/itext.tests/itext.layout.tests/itext/layout/TextWritingTest.cs index aa1bbaa2f3..0b7303b3a0 100644 --- a/itext.tests/itext.layout.tests/itext/layout/TextWritingTest.cs +++ b/itext.tests/itext.layout.tests/itext/layout/TextWritingTest.cs @@ -87,6 +87,11 @@ public virtual void TextRenderingModeTest01() { .FILL_STROKE).SetStrokeColor(ColorConstants.BLUE).SetStrokeWidth(0.3f).SetFontColor(ColorConstants.GREEN ).SetFontSize(20); document.Add(new Paragraph(text3)); + Text text4 = new Text("This is a stroke with dashes text").SetTextRenderingMode(PdfCanvasConstants.TextRenderingMode + .FILL_STROKE).SetStrokeColor(ColorConstants.BLUE).SetStrokeWidth(0.5f).SetFontColor(ColorConstants.PINK + ).SetFontSize(20); + text4.SetDashPattern(new float[] { 0.5f, 1f }, 0f); + document.Add(new Paragraph(text4)); document.Close(); NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(outFileName, cmpFileName, destinationFolder , "diff")); @@ -281,10 +286,11 @@ public virtual void StrokedUnderlineTest() { String cmpFileName = sourceFolder + "cmp_strokedUnderline.pdf"; using (PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outFileName))) { using (Document document = new Document(pdfDocument)) { - Paragraph p = new Paragraph("Yellow text with pink stroked underline.").SetFontSize(50).SetFontColor(ColorConstants - .YELLOW); + Paragraph p = new Paragraph("Yellow text with pink stroked dashed underline.").SetFontSize(45).SetFontColor + (ColorConstants.YELLOW); Underline underline = new Underline(null, 0, 0.1f, 0, -0.1f, PdfCanvasConstants.LineCapStyle.BUTT).SetStrokeWidth - (2).SetStrokeColor(new TransparentColor(ColorConstants.PINK, 0.5f)); + (2).SetStrokeColor(new TransparentColor(ColorConstants.PINK, 0.5f)).SetDashPattern(new float[] { 5, 5, + 10, 5 }, 5); p.SetUnderline(underline); Paragraph p2 = new Paragraph("Text with line-through and default underline.").SetFontSize(50).SetStrokeWidth (1).SetFontColor(ColorConstants.DARK_GRAY).SetStrokeColor(ColorConstants.GREEN); @@ -292,7 +298,7 @@ public virtual void StrokedUnderlineTest() { .BUTT).SetStrokeWidth(1).SetStrokeColor(new TransparentColor(ColorConstants.GREEN)); p2.SetUnderline(underline2); p2.SetUnderline(); - Paragraph p3 = new Paragraph("Text with transparent font color and default overline.").SetFontSize(50).SetFontColor + Paragraph p3 = new Paragraph("Text with transparent color and default overline.").SetFontSize(50).SetFontColor (new TransparentColor(ColorConstants.BLUE, 0)); Underline underline3 = new Underline(null, 0, 0.1f, 0, 0.9f, PdfCanvasConstants.LineCapStyle.BUTT); p3.SetUnderline(underline3); diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/TextWritingTest/cmp_strokedUnderline.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/TextWritingTest/cmp_strokedUnderline.pdf index 55915462a603d8d8da3cd623b6714b5ac9dd1951..eea14a3b3f34988f18040f5420a6b011d461ca76 100644 GIT binary patch delta 1000 zcmdnRe}R93X}zh5on3KBQEFl?SH+yE!PdoB9C+S+4`0E`1$UZw5xBHzgK+ec~|t+x5bS90c)mk3!GehJ|N^&10(O>sJk_5 zXD_>bIO4xt;(l544?A+@?}^%9kk~ijnf(&B6}}le6ddDM>j!TSj#YHM@+IiH!MD54v5uj9(t5kMt@@pI``Qn- z&~KYoO)#-iIDG5TB8^MzfmRDXD|szeohv*iY+|HLv2fx0w?=Lm%QZBmY57riLGTq$RS9_DM zKQ(^)GQ5?JTqa9>g2OQx#hmhtJldUZmLT2FPL&6 z$}UKGdDYJSAEUOp{5t==^kn-VKR(_5_LQstw*F-f;4_%N`2(W|BfGhwsi}pj$z*$G zDHwZm0`pTwJ2MLf0}xQiQ{VzK3=9p-jnTynEDSNlOpVPZH?yjxSeT+KH#9Ud!4xw! z#1u2fwBE=7!zx3g$ro9LwT(UJlW3e~4s@k)Qc{X# zqNR~pnyGQ3X;NycaiS4WNwSHliFvA7ie)lTIw{2rC~9n(mXv6bW?+^KCqpSR|UI0reUg0F6#GO9ck5sbz|VMT)t3lA(oZVq%IxeTtpU ZKstd1=!TTZ>Fi#d#>QN#s;>TSTmWL&a8UpN delta 1005 zcmcb>zl(o@X}z(Lon3KBQEFl?SH+yEQ>@Ex8}PK2|KsX;DZoLcQyU_8@G!6>!f$Wn>KL1f8JkRUs}BX>V{id%)gyW zdmWoUx7=!O-xp@j{&6KQA75|HmW{o&-$TMTWUtA&0@S}5@* z&`pBvX_3{mw32T@Yh0rpL+ka$cdPl8|LShsBd9aUSaHgKP8ZfLyHj>-R`WkPCPysZ z-kEW5#+CjLmHczIzG(ldb|Nphaf^zX{>h958{@a!e(oB-{bS8M<+-PK#h4ld8O{Cn zdPb>K{@w-CgZIdPIK8g-!wu6|{>74KKK(qQ-mAjAf5ubkjVEeO@iXuLZEX1ZqMdGK zbL8O_l3PxwN(A0J%ObsX+g(%MKiySg`mg64HSt=1S$odv^}Xj;PkP-yy-dq}-`S>b zA6^?O->zqLy{hqhGaHi!qlSs0si~2%nYMwkx`BbZroL}}ic4Zis)mb|k%5t^fuSK( z!R9jNr;K(cW(o!%ppd7)1!fo+8kicQiy4?(Vv3m>noOR_swQS;jIP|!(7|GBC%`Yh;XRlaVQ=9Yz+W5WSPr*+lA%Ee%prQjLr)%*@TqElkqV zlFgD6EmDn46M?~zmST|%L}r$W#z{s-78d5li3SFy#%87_CKl#qX=z3ViKfPespcl8 ziAjcO<|Za4#>Qrr<|)Z(CYGkA$;JkzNhYRArWWQ##)&B@X2u37NoFR=$p(hW1}4Tv i2BzkT^%izE1L*`7pc^bE*Rp$Y8X9t`s=E5SaRC6Y-C-dB diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/TextWritingTest/cmp_textRenderingModeTest01.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/TextWritingTest/cmp_textRenderingModeTest01.pdf index 6e140f81c42c035032a161056f3cd5e51d40bb18..e97496b945fffc31a8d59f34120786c825937a72 100644 GIT binary patch literal 1269 zcmc&zNoW*76jhKRv`eD6pX%U{1f6tM?-S!dGLtc)Nrp+>h=Zx=u8yr^ckJ$oNdym~ z7)3AQ0>*q-y7ve3J!gO5&DZ<|=iWf}*!zj~^b%{`=)aiOX2XD`mFJMk&J|IYg!{(Admd|!W} zeO`R{AxtMq21ApNXNTvtwKq(y{faN$xR>0CuHL!1d|Bwr<1^pq^nV;$Gd};;$_1&X znaaMB>T}}*BUSZ^cfj7f^xOD@k7IjA`zm60Z>now_pkdppiidXzPwU8(R}v!q9yZ2 zkDZz|G~|Wu?mIm!_MKQ&dNkHJIoZ^&t~h`D*{R<1Q=zeu_BR}{jY2VW$BLJVB*Y!t zC${eaMogM-B!-3SobEPAk8)H7nj~cS6m}^F2mvHbJSXq!#A6gvZ?+(yu)7!?e5-5i zoe`n6r<2ey9V8ZG>98aa^(ZL8F1$kc02#+V&N&@Luvi4gsVu(b*a<3IMWR}Of(#K- z=z<_z4aIT@%PaXt$M`oOVf!;mf^KAHPe}&9s!d@mu{Ds z90V#y(=H64$g(H{6a2DCFbaY@VE?wMhz4cj51S;UnilAy}P@)oMiK;~v6`P`zk9@4`|?rh5!Hn literal 1017 zcmah|T}TvB7$uU30inzaD&#^ey2N_#ote8oAq%eSs^!nJyH=o5v%7b<$#q6%?#e0^ zB+^qvJrs!{Q7=W%gHIJfWJDlYh80CZSZ@jiMnQ?tz1!%5K6qbt=FIuNJ@=gNb49}u z53cn|uCL$T%t{y_U?$HF&L^aL%i2f$m4YLO@2ULTD& zcO<|)86o81?Nv}DfF{e#_k;Fhpu48NDcb58pq9;rbi3Upq27|vkY>|}X)pkrX>Ncr zJ*B}$BW0#_BMabh-KaNgeHDQ5e3BLKE*!v)52C!(TR7xc)?ns&V+@b#X&ZE@!nz)( zrs!s=NPJr>G8i?O4T#{wHk#J8kXZm-h`*Bn0e)5P;b~Z$Lb!l$3~nb(BQ(9OK5rNREdXrrZ+>Td9#{rvWB77_=D=xlbzG z%)fpnO`;uTGt1{+RQ)>DI&tFj{afSLRxTv>_m!8o9bEV_Rxxtq>geo&s@dn4wR6$C z>cp0*{;|Eo+aC=-EL;iA@2Z@-@pI>%v%T9cdETlYlAk*LWk0@?i+^`tpPL+?FI$i cg2l(UK16|!M{P6BVnsK6iY&QYjU5r`AE;3~jQ{`u diff --git a/itext.tests/itext.svg.tests/itext/svg/renderers/StrokeTest.cs b/itext.tests/itext.svg.tests/itext/svg/renderers/StrokeTest.cs index 958f2fc1ab..0ddf79d32d 100644 --- a/itext.tests/itext.svg.tests/itext/svg/renderers/StrokeTest.cs +++ b/itext.tests/itext.svg.tests/itext/svg/renderers/StrokeTest.cs @@ -55,7 +55,6 @@ public virtual void NoLineStrokeWidthTest() { [NUnit.Framework.Test] public virtual void StrokeWithDashesTest() { // TODO DEVSIX-8774 support stroke-opacity for text at layout level - // TODO DEVSIX-8776 support dash-pattern in layout ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "strokeWithDashes"); } diff --git a/itext.tests/itext.svg.tests/itext/svg/renderers/impl/TSpanNodeRendererIntegrationTest.cs b/itext.tests/itext.svg.tests/itext/svg/renderers/impl/TSpanNodeRendererIntegrationTest.cs index 900abe099b..55c5a89627 100644 --- a/itext.tests/itext.svg.tests/itext/svg/renderers/impl/TSpanNodeRendererIntegrationTest.cs +++ b/itext.tests/itext.svg.tests/itext/svg/renderers/impl/TSpanNodeRendererIntegrationTest.cs @@ -236,6 +236,11 @@ public virtual void TextDecorationStyleTest() { ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "textDecorationStyle"); } + [NUnit.Framework.Test] + public virtual void TextDecorationDashedStrokeTest() { + ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "textDecorationDashedStroke"); + } + [NUnit.Framework.Test] public virtual void TspanDefaultFontSizeTest() { ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "tspanDefaultFontSize"); diff --git a/itext.tests/itext.svg.tests/itext/svg/renderers/impl/TextSvgBranchRendererIntegrationTest.cs b/itext.tests/itext.svg.tests/itext/svg/renderers/impl/TextSvgBranchRendererIntegrationTest.cs index 0571a8f393..5d69685143 100644 --- a/itext.tests/itext.svg.tests/itext/svg/renderers/impl/TextSvgBranchRendererIntegrationTest.cs +++ b/itext.tests/itext.svg.tests/itext/svg/renderers/impl/TextSvgBranchRendererIntegrationTest.cs @@ -271,13 +271,11 @@ public virtual void TextCombinedAttributesTest() { [NUnit.Framework.Test] public virtual void TextStrokeDasharrayTest() { - //TODO: DEVSIX-8776 Support stroke dash pattern in layout ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "textStrokeDasharray"); } [NUnit.Framework.Test] public virtual void TextComplexStrokeDasharrayTest() { - //TODO: DEVSIX-8776 Support stroke dash pattern in layout ConvertAndCompareSinglePage(SOURCE_FOLDER, DESTINATION_FOLDER, "textComplexStrokeDasharray"); } diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/StrokeTest/cmp_strokeWithDashes.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/StrokeTest/cmp_strokeWithDashes.pdf index d2351bea4a13641a79266fbbf086d2fcf1ec2c8f..cb7c87c97f57ec99dd3e813cdd1d6bba616947f6 100644 GIT binary patch delta 396 zcmc(ZJxT;Y6olz@!DTSi$fT2HT$J&>*RNl9ix{oS2I2w4pns-Q6OA`Cmbr*9nVBc? z2wuUF#WM(1P+w6&eI33Yy=%2X0Wxgi6if@yuFmhC$~r#xC+iCWvVebsVWV!99pBW8 znh}nRy^neO;5w^!rl3tHI}(j{(xW!gvDIb#+&@z@gyDN}yv-7zx*8a2ke+LeCAsP? z2|%7wC6*M}LyUreBz^Q$Fa;rRQi5qo8ND-!V?;KYvDSn!CzQe*xj2`QAWmgATz{DW fBbIL1!ZdO*CND_BKOX{b7w{ttBtaS_yAV3^8H E L L O + stroke-dasharray="10 10 1% 0.5% 0.1em 0.5rem 20 20" + stroke-dashoffset="5%">H E L L O diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/TSpanNodeRendererIntegrationTest/cmp_textDecorationDashedStroke.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/TSpanNodeRendererIntegrationTest/cmp_textDecorationDashedStroke.pdf new file mode 100644 index 0000000000000000000000000000000000000000..747acce6320386dd81c901a29830245be3aa1464 GIT binary patch literal 2703 zcmc&$Np9pe6y5U_+!WeIP!b1Glmepw&uOH)?Jf)H0B$c-5>=MrlH8QacIQUfi)UN8^=eY()>*VLgZ5aR2)-Z|xmKuQMC- z+AMFV6^$AA7V2s>C_--(hp-}jImKrE)xw~t-noPT){sx6g8VRPPRFN&dx}0lr51(* zN&;Q?6U7k-xN;^JFrW()J0+J+0}X`-q=J{L&M5C;0=G`(0j$1|g9PTB(?HRr=oJ8G z2*epj`(#E0O)R-YkDW7`lbz(+8nc_+kmJOKcLvgnz%20MfJ!gMat@sE`50WssQGFf zSHc723j-M=u!}du20p?-GhBwccj!ZH^JXolEro^YhLg>*`f$t4q{pCW0YFHqykJ$) zzjYm{mpng@m4s$+{RFEeBcR35734Yc1?dAE>>$!g0Lq{lhb-!Vx=!!cd-sovS!U&M zibGHE{|Khua|hEij(e0sw!vB%YfmBtH<`PIlEg7`Aicz;OHM4HoFhbXY-uW^U>4^w74j7z>Y7h3K}^@WX|h)S(hH8b0GE1W#6LcJM|iZRfa+obCtUx~P$}4-3%Xbn zFj-DUtL2)KkQF{_Ya)bwd25Y95>M7RY>``fLGaX{ilCocdJ$Xm*V?qaH5TtiZ;$BZ zo(x%NA`?Z@OiUUSe4 + + + + + + Three + + words + + have + + + + different + + + + underlining + + + + \ No newline at end of file diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/TextSvgBranchRendererIntegrationTest/cmp_textComplexStrokeDasharray.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/TextSvgBranchRendererIntegrationTest/cmp_textComplexStrokeDasharray.pdf index 3efa551cd0d73a0be4933e1c0abede4de1330874..3af902154d9dd0555f79a948ee651ba9d9970ab9 100644 GIT binary patch delta 484 zcmc(aO-chn5QP~NT@1SO0F4q75yq9?nT!&&wNRr7OqERjV*lh!wGt61(QULQreM0-1q)uy zZ`-Hd@$QPou0m31D)Nea#deiv%7T*iy|=Ud&HDpb>wheng9+Buu}PT8NZpC26ilN9 ztt1_D9il`}+6MxI#y2+TY`foc5@JD0l2V<~P_7v~29TIgBq!q;H9HO@o<)2IBAZeU gIf|*Z;eg9@H2zP8e&>+d&-H1E4$Hyd~$ZilqB0}u$`HP5)sBaSl@d7<>dRz(;aA(dSa}hzWA$T2k zM(_@e7booYu?IoeMUeI@K0!i8kBv1Ra>Q~O(!oi z)b~$4uAF}EQNzmH0A7Q>yJ?@3%kGyp=#JV$_q}7zFml2S#c;8L5K<^rVsfblLn&87 zp^9KM=#a=q>nl|7BQkQy*?0*q1|b(BiOaQObs~_N8B9%(%vh}}7Gl}&5Qdx~z$hFo Z@65&deNQ>NEfs$+15CYPT`Co0>tjO`|Y*h z-tX6q)pAL`5O2I>Ff!yFA-YoQWqflc!PazWszz5$4bI)nd#hC`kIn6z;?$?@@4}l( zi+g~#TV}d8E1T;Yfj>;LOPx3P=FlSdy^oKV+H$$$CH;D>(bYot`z|CG2t$i?4(>y} zhG=&VWh1Z5V!PSjZXRNiO=+r;Z1lnCXHL1GjD?i*K(L>v|BBLAhu&MGzP({;jauc} z9+auRZT^Cxu^N&d>(TD{*Ki^ zYdHJua2sp5jrCa8dWzRDWMlcRvOqvwpb zo?Q{vlnu=atHQirOI6QZO=lN(7A==s6IYkD$?;BA*4hb}_k3Yv=esTJeRyMImv>le z32c<-N=l*Y{+xdDCFwwYvjA&M^MWiL%u8`b{^LL$IZl2I9Od5|?Ftjh^ zIK{SM7&oLvtIal%s3*X8L%Jj!QcLD;g1-wlfFcaX--+|dV0P*Zdy(J?R-_jtA&tQ< z$iX11&DE;WFp~9Wm>i~;Vz=QYS$a zaN*;(JPN~{`RK2RW1lC5DvFFUzo1;jdH=^paN)hK3IpysoOv@mR$>v{PH-d=d@ eciQW$>u$5|&>OTl2hR69@O^E(t-X$msArSre17;kNVF)l+67q!sMZ^ogS44sRBP@F z5E}3ogtJ1spu(*1nSX}c;=_Es7hCJ7;l6P}{l~1w(LyLMowNMLhs5q!Kk((P@Um3i zM&21R+|zu*fCEQ<(`L0}HyS*RGioNIUN|b%cZ}wpXZFWpZed}sY3Qk+E$HUT_Y~t; zd6P)(9HcP_?>!-OMM4^#*A$WUX)J}3Iu+Ika)u14D7Hd+;k@-K1;QwT1a;)BbrvX2 zOx#t8bO||`ht>*ZAWcOijYVrn8>6~DwJ?>32me{2ly{I}wS3AzA*)nQu3GE|!+n3w diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/TextSvgBranchRendererIntegrationTest/textComplexStrokeDasharray.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/TextSvgBranchRendererIntegrationTest/textComplexStrokeDasharray.svg index 659a0f7f6d..11d9e2f3e0 100644 --- a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/TextSvgBranchRendererIntegrationTest/textComplexStrokeDasharray.svg +++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/TextSvgBranchRendererIntegrationTest/textComplexStrokeDasharray.svg @@ -1,9 +1,11 @@ - + AbsoluteComplex - + PercentComplex diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/TextSvgBranchRendererIntegrationTest/textStrokeDasharray.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/TextSvgBranchRendererIntegrationTest/textStrokeDasharray.svg index 40afcfd245..33c6620a15 100644 --- a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/TextSvgBranchRendererIntegrationTest/textStrokeDasharray.svg +++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/impl/TextSvgBranchRendererIntegrationTest/textStrokeDasharray.svg @@ -1,9 +1,25 @@ - - - AbsoluteDash + + + Absolute Dash O - - PercentDash + + Percent Dash O + + + + Zero Dash O + + + + Negative Dash O + + + + Odd Dash O + + + + Relative Dash O diff --git a/itext/itext.kernel/itext/kernel/pdf/canvas/PdfCanvas.cs b/itext/itext.kernel/itext/kernel/pdf/canvas/PdfCanvas.cs index fa420089fd..4467af2763 100644 --- a/itext/itext.kernel/itext/kernel/pdf/canvas/PdfCanvas.cs +++ b/itext/itext.kernel/itext/kernel/pdf/canvas/PdfCanvas.cs @@ -1290,7 +1290,11 @@ public virtual iText.Kernel.Pdf.Canvas.PdfCanvas SetMiterLimit(float miterLimit) /// the value of the phase /// current canvas. public virtual iText.Kernel.Pdf.Canvas.PdfCanvas SetLineDash(float phase) { - currentGs.SetDashPattern(GetDashPatternArray(phase)); + PdfArray dashPattern = GetDashPatternArray(phase); + if (dashPattern == null) { + return this; + } + currentGs.SetDashPattern(dashPattern); contentStream.GetOutputStream().WriteByte('[').WriteByte(']').WriteSpace().WriteFloat(phase).WriteSpace(). WriteBytes(d); return this; @@ -1310,7 +1314,11 @@ public virtual iText.Kernel.Pdf.Canvas.PdfCanvas SetLineDash(float phase) { /// /// current canvas. public virtual iText.Kernel.Pdf.Canvas.PdfCanvas SetLineDash(float unitsOn, float phase) { - currentGs.SetDashPattern(GetDashPatternArray(new float[] { unitsOn }, phase)); + PdfArray dashPattern = GetDashPatternArray(new float[] { unitsOn }, phase); + if (dashPattern == null) { + return this; + } + currentGs.SetDashPattern(dashPattern); contentStream.GetOutputStream().WriteByte('[').WriteFloat(unitsOn).WriteByte(']').WriteSpace().WriteFloat( phase).WriteSpace().WriteBytes(d); return this; @@ -1330,7 +1338,11 @@ public virtual iText.Kernel.Pdf.Canvas.PdfCanvas SetLineDash(float unitsOn, floa /// the number of units that must be 'off' /// current canvas. public virtual iText.Kernel.Pdf.Canvas.PdfCanvas SetLineDash(float unitsOn, float unitsOff, float phase) { - currentGs.SetDashPattern(GetDashPatternArray(new float[] { unitsOn, unitsOff }, phase)); + PdfArray dashPattern = GetDashPatternArray(new float[] { unitsOn, unitsOff }, phase); + if (dashPattern == null) { + return this; + } + currentGs.SetDashPattern(dashPattern); contentStream.GetOutputStream().WriteByte('[').WriteFloat(unitsOn).WriteSpace().WriteFloat(unitsOff).WriteByte (']').WriteSpace().WriteFloat(phase).WriteSpace().WriteBytes(d); return this; @@ -1349,7 +1361,11 @@ public virtual iText.Kernel.Pdf.Canvas.PdfCanvas SetLineDash(float unitsOn, floa /// the value of the phase /// current canvas. public virtual iText.Kernel.Pdf.Canvas.PdfCanvas SetLineDash(float[] array, float phase) { - currentGs.SetDashPattern(GetDashPatternArray(array, phase)); + PdfArray dashPattern = GetDashPatternArray(array, phase); + if (dashPattern == null) { + return this; + } + currentGs.SetDashPattern(dashPattern); PdfOutputStream @out = contentStream.GetOutputStream(); @out.WriteByte('['); for (int iter = 0; iter < array.Length; iter++) { @@ -2355,9 +2371,19 @@ private PdfArray GetDashPatternArray(float[] dashArray, float phase) { PdfArray dashPatternArray = new PdfArray(); PdfArray dArray = new PdfArray(); if (dashArray != null) { + float sum = 0; foreach (float fl in dashArray) { + if (fl < 0) { + // Negative values are not allowed. + return null; + } + sum += fl; dArray.Add(new PdfNumber(fl)); } + if (sum < 1e-6) { + // All 0 values are not allowed. + return null; + } } dashPatternArray.Add(dArray); dashPatternArray.Add(new PdfNumber(phase)); diff --git a/itext/itext.layout/itext/layout/ElementPropertyContainer.cs b/itext/itext.layout/itext/layout/ElementPropertyContainer.cs index 2bed6184f9..4914a79a5c 100644 --- a/itext/itext.layout/itext/layout/ElementPropertyContainer.cs +++ b/itext/itext.layout/itext/layout/ElementPropertyContainer.cs @@ -653,6 +653,38 @@ public virtual T SetStrokeColor(Color strokeColor) { return (T)(Object)this; } + /// Sets the stroke dash pattern for the current text. + /// + /// Sets the stroke dash pattern for the current text. Dash pattern is an array of the form [ dashArray dashPhase ], + /// where + /// + /// is a float array that specifies the length of the alternating dashes and gaps, + /// + /// is a float that specifies the distance into the dash pattern to start the dash. + /// + /// + /// float array that specifies the length of the alternating dashes and gaps, + /// use + /// + /// for solid line + /// + /// + /// float that specifies the distance into the dash pattern to start the dash, + /// use 0 in case offset isn't needed + /// + /// this element + public virtual T SetDashPattern(float[] dashArray, float dashPhase) { + IList dashPattern = new List(); + if (dashArray != null) { + foreach (float fl in dashArray) { + dashPattern.Add(fl); + } + } + dashPattern.Add(dashPhase); + SetProperty(Property.STROKE_DASH_PATTERN, dashPattern); + return (T)(Object)this; + } + /// Gets the stroke width for the current element. /// /// Gets the stroke width for the current element. diff --git a/itext/itext.layout/itext/layout/properties/Property.cs b/itext/itext.layout/itext/layout/properties/Property.cs index a0e3fc3655..31b2db7ec1 100644 --- a/itext/itext.layout/itext/layout/properties/Property.cs +++ b/itext/itext.layout/itext/layout/properties/Property.cs @@ -330,6 +330,19 @@ public sealed class Property { public const int STROKE_COLOR = 63; + /// + /// STROKE_DASH_PATTERN property specifies dash pattern for the text stroke and stores the + /// + /// as float array of the form [ dashArray dashPhase ], where + /// dashArray + /// is a float array that specifies + /// the length of the alternating dashes and gaps, + /// dashPhase + /// is a float that specifies the distance into + /// the dash pattern to start the dash. + /// + public const int STROKE_DASH_PATTERN = 156; + public const int STROKE_WIDTH = 64; public const int SKEW = 65; @@ -404,7 +417,7 @@ public sealed class Property { /// private static readonly bool[] INHERITED_PROPERTIES; - private const int MAX_INHERITED_PROPERTY_ID = 155; + private const int MAX_INHERITED_PROPERTY_ID = 156; static Property() { INHERITED_PROPERTIES = new bool[MAX_INHERITED_PROPERTY_ID + 1]; @@ -434,6 +447,7 @@ static Property() { INHERITED_PROPERTIES[iText.Layout.Properties.Property.SPACING_RATIO] = true; INHERITED_PROPERTIES[iText.Layout.Properties.Property.SPLIT_CHARACTERS] = true; INHERITED_PROPERTIES[iText.Layout.Properties.Property.STROKE_COLOR] = true; + INHERITED_PROPERTIES[iText.Layout.Properties.Property.STROKE_DASH_PATTERN] = true; INHERITED_PROPERTIES[iText.Layout.Properties.Property.STROKE_WIDTH] = true; INHERITED_PROPERTIES[iText.Layout.Properties.Property.TEXT_ALIGNMENT] = true; INHERITED_PROPERTIES[iText.Layout.Properties.Property.TEXT_ANCHOR] = true; diff --git a/itext/itext.layout/itext/layout/properties/Underline.cs b/itext/itext.layout/itext/layout/properties/Underline.cs index 6759356415..248e3f0a59 100644 --- a/itext/itext.layout/itext/layout/properties/Underline.cs +++ b/itext/itext.layout/itext/layout/properties/Underline.cs @@ -49,6 +49,10 @@ public class Underline { private float strokeWidth = 0f; + private float[] dashArray = null; + + private float dashPhase = 0f; + /// Creates an Underline. /// /// Creates an Underline. Both the thickness and vertical positioning under @@ -210,5 +214,58 @@ public virtual iText.Layout.Properties.Underline SetStrokeWidth(float strokeWidt this.strokeWidth = strokeWidth; return this; } + + /// Gets dash array part of the dash pattern to be used when paths are stroked. + /// + /// Gets dash array part of the dash pattern to be used when paths are stroked. Default value is solid line. + /// + /// The line dash pattern is expressed as an array of the form [ dashArray dashPhase ], + /// where dashArray is itself an array and dashPhase is an integer. + /// + /// An empty dash array (first element in the array) and zero phase (second element in the array) + /// can be used to restore the dash pattern to a solid line. + /// + /// float dash array + public virtual float[] GetDashArray() { + return dashArray; + } + + /// Gets dash phase part of the dash pattern to be used when paths are stroked. + /// + /// Gets dash phase part of the dash pattern to be used when paths are stroked. Default value is solid line. + /// + /// The line dash pattern is expressed as an array of the form [ dashArray dashPhase ], + /// where dashArray is itself an array and dashPhase is an integer. + /// + /// An empty dash array (first element in the array) and zero phase (second element in the array) + /// can be used to restore the dash pattern to a solid line. + /// + /// float dash array + public virtual float GetDashPhase() { + return dashPhase; + } + + /// Sets a description of the dash pattern to be used when paths are stroked. + /// + /// Sets a description of the dash pattern to be used when paths are stroked. Default value is solid line. + /// + /// The line dash pattern is expressed as an array of the form [ dashArray dashPhase ], + /// where dashArray is itself an array and dashPhase is a number. + /// + /// An empty dash array (first element in the array) and zero phase (second element in the array) + /// can be used to restore the dash pattern to a solid line. + /// + /// dash array + /// dash phase value + /// + /// this same + /// + /// instance + /// + public virtual iText.Layout.Properties.Underline SetDashPattern(float[] dashArray, float dashPhase) { + this.dashArray = dashArray; + this.dashPhase = dashPhase; + return this; + } } } diff --git a/itext/itext.layout/itext/layout/renderer/TextRenderer.cs b/itext/itext.layout/itext/layout/renderer/TextRenderer.cs index ff74e8ef46..74d5a3351b 100644 --- a/itext/itext.layout/itext/layout/renderer/TextRenderer.cs +++ b/itext/itext.layout/itext/layout/renderer/TextRenderer.cs @@ -851,6 +851,15 @@ public override void Draw(DrawContext drawContext) { } if (textRenderingMode == PdfCanvasConstants.TextRenderingMode.STROKE || textRenderingMode == PdfCanvasConstants.TextRenderingMode .FILL_STROKE) { + IList strokeDashPattern = this.GetProperty>(Property.STROKE_DASH_PATTERN); + if (strokeDashPattern != null && !strokeDashPattern.IsEmpty()) { + float[] dashArray = new float[strokeDashPattern.Count - 1]; + for (int i = 0; i < strokeDashPattern.Count - 1; ++i) { + dashArray[i] = strokeDashPattern[i]; + } + float dashPhase = strokeDashPattern[strokeDashPattern.Count - 1]; + canvas.SetLineDash(dashArray, dashPhase); + } if (strokeWidth == null) { strokeWidth = this.GetPropertyAsFloat(Property.STROKE_WIDTH); } @@ -1486,6 +1495,10 @@ protected internal virtual void DrawSingleUnderline(Underline underline, Transpa if (doStroke) { canvas.SetStrokeColor(underlineStrokeColor.GetColor()); underlineStrokeColor.ApplyStrokeTransparency(canvas); + float[] strokeDashArray = underline.GetDashArray(); + if (strokeDashArray != null) { + canvas.SetLineDash(strokeDashArray, underline.GetDashPhase()); + } } canvas.SetLineCapStyle(underline.GetLineCapStyle()); float underlineThickness = underline.GetThickness(fontSize); diff --git a/itext/itext.svg/itext/svg/renderers/impl/TextLeafSvgNodeRenderer.cs b/itext/itext.svg/itext/svg/renderers/impl/TextLeafSvgNodeRenderer.cs index 2517de8e42..9d680d8a29 100644 --- a/itext/itext.svg/itext/svg/renderers/impl/TextLeafSvgNodeRenderer.cs +++ b/itext/itext.svg/itext/svg/renderers/impl/TextLeafSvgNodeRenderer.cs @@ -129,10 +129,10 @@ private void ApplyTransform(SvgDrawContext context) { private void ApplyGraphicsState(SvgDrawContext context) { SvgTextProperties textProperties = context.GetSvgTextProperties(); // TODO DEVSIX-8774 support stroke-opacity for text at layout level - // TODO DEVSIX-8776 support dash-pattern in layout text.SetFontColor(textProperties.GetFillColor()); text.SetStrokeWidth(textProperties.GetLineWidth()); text.SetStrokeColor(textProperties.GetStrokeColor()); + text.SetDashPattern(textProperties.GetDashArray(), textProperties.GetDashPhase()); text.SetOpacity(textProperties.GetFillOpacity()); text.SetProperty(Property.UNDERLINE, textProperties.GetTextDecoration()); } diff --git a/itext/itext.svg/itext/svg/utils/SvgTextProperties.cs b/itext/itext.svg/itext/svg/utils/SvgTextProperties.cs index 4585f4e734..739d2ce796 100644 --- a/itext/itext.svg/itext/svg/utils/SvgTextProperties.cs +++ b/itext/itext.svg/itext/svg/utils/SvgTextProperties.cs @@ -21,9 +21,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ using System.Collections.Generic; -using iText.Commons.Utils; using iText.Kernel.Colors; -using iText.Kernel.Pdf; using iText.Layout.Properties; namespace iText.Svg.Utils { @@ -51,8 +49,9 @@ public class SvgTextProperties { private float strokeOpacity = 1f; - private PdfArray dashPattern = new PdfArray(JavaUtil.ArraysAsList(new PdfObject[] { new PdfArray(), new PdfNumber - (0) })); + private float[] dashArray = null; + + private float dashPhase = 0f; private float lineWidth = 1f; @@ -82,7 +81,8 @@ public SvgTextProperties(iText.Svg.Utils.SvgTextProperties textProperties) { this.strokeColor = textProperties.GetStrokeColor(); this.fillOpacity = textProperties.GetFillOpacity(); this.strokeOpacity = textProperties.GetStrokeOpacity(); - this.dashPattern = textProperties.GetDashPattern(); + this.dashArray = textProperties.GetDashArray(); + this.dashPhase = textProperties.GetDashPhase(); this.lineWidth = textProperties.GetLineWidth(); this.textDecoration = textProperties.GetTextDecoration(); } @@ -214,9 +214,9 @@ public virtual iText.Svg.Utils.SvgTextProperties SetTextDecoration(IListGets a description of the dash pattern to be used when paths are stroked. + /// Gets dash array part of the dash pattern to be used when paths are stroked. /// - /// Gets a description of the dash pattern to be used when paths are stroked. Default value is solid line. + /// Gets dash array part of the dash pattern to be used when paths are stroked. Default value is solid line. /// /// The line dash pattern is expressed as an array of the form [ dashArray dashPhase ], /// where dashArray is itself an array and dashPhase is an integer. @@ -224,10 +224,24 @@ public virtual iText.Svg.Utils.SvgTextProperties SetTextDecoration(IList - /// dash pattern array - public virtual PdfArray GetDashPattern() { - // TODO DEVSIX-8776 support dash-pattern in layout - return dashPattern; + /// float dash array + public virtual float[] GetDashArray() { + return dashArray; + } + + /// Gets dash phase part of the dash pattern to be used when paths are stroked. + /// + /// Gets dash phase part of the dash pattern to be used when paths are stroked. Default value is solid line. + /// + /// The line dash pattern is expressed as an array of the form [ dashArray dashPhase ], + /// where dashArray is itself an array and dashPhase is an integer. + /// + /// An empty dash array (first element in the array) and zero phase (second element in the array) + /// can be used to restore the dash pattern to a solid line. + /// + /// float dash array + public virtual float GetDashPhase() { + return dashPhase; } /// Sets a description of the dash pattern to be used when paths are stroked. @@ -248,21 +262,9 @@ public virtual PdfArray GetDashPattern() { /// instance /// public virtual iText.Svg.Utils.SvgTextProperties SetDashPattern(float[] dashArray, float dashPhase) { - this.dashPattern = GetDashPatternArray(dashArray, dashPhase); + this.dashArray = dashArray; + this.dashPhase = dashPhase; return this; } - - private static PdfArray GetDashPatternArray(float[] dashArray, float phase) { - PdfArray dashPatternArray = new PdfArray(); - PdfArray dArray = new PdfArray(); - if (dashArray != null) { - foreach (float fl in dashArray) { - dArray.Add(new PdfNumber(fl)); - } - } - dashPatternArray.Add(dArray); - dashPatternArray.Add(new PdfNumber(phase)); - return dashPatternArray; - } } } diff --git a/itext/itext.svg/itext/svg/utils/SvgTextUtil.cs b/itext/itext.svg/itext/svg/utils/SvgTextUtil.cs index f8ebaab9bd..623f14cd5e 100644 --- a/itext/itext.svg/itext/svg/utils/SvgTextUtil.cs +++ b/itext/itext.svg/itext/svg/utils/SvgTextUtil.cs @@ -294,13 +294,15 @@ private static void AddUnderline(SvgDrawContext context, IList underl if (doStroke && doFill) { underline = new Underline(fillColor, fillOpacity, context.GetSvgTextProperties().GetLineWidth(), 0.07f, 0, textDecorationLine, PdfCanvasConstants.LineCapStyle.BUTT).SetStrokeColor(new TransparentColor(strokeColor - , strokeOpacity)).SetStrokeWidth(context.GetSvgTextProperties().GetLineWidth()); + , strokeOpacity)).SetStrokeWidth(context.GetSvgTextProperties().GetLineWidth()).SetDashPattern(context + .GetSvgTextProperties().GetDashArray(), context.GetSvgTextProperties().GetDashPhase()); } else { if (doStroke) { underline = new Underline(null, 0, context.GetSvgTextProperties().GetLineWidth(), 0.07f, 0, textDecorationLine , PdfCanvasConstants.LineCapStyle.BUTT).SetStrokeColor(new TransparentColor(strokeColor, strokeOpacity - )).SetStrokeWidth(context.GetSvgTextProperties().GetLineWidth()); + )).SetStrokeWidth(context.GetSvgTextProperties().GetLineWidth()).SetDashPattern(context.GetSvgTextProperties + ().GetDashArray(), context.GetSvgTextProperties().GetDashPhase()); } else { underline = new Underline(fillColor, fillOpacity, 0, 0.07f, 0, textDecorationLine, PdfCanvasConstants.LineCapStyle diff --git a/port-hash b/port-hash index 846f9abca4..3fbb2a8a11 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -97c3ae4142bc0b9cb2ff210e32a9138150c5fe15 +0bedf083f369de46e46d36611825e88a85204b49