From 468464ccce9cb7a434c297bbac51e36a139d89da Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Sat, 16 May 2020 14:31:54 +0200 Subject: [PATCH] Implement custom svg document loader, allow to use the internal user agent. Implement #444 --- .../com/openhtmltopdf/extend/SVGDrawer.java | 14 +++--- .../expected/svg-custom-protocol.pdf | Bin 0 -> 1362 bytes .../svg-external-file-load-blocked.pdf | Bin 0 -> 784 bytes ...-external-file-whitelist-file-protocol.pdf | Bin 0 -> 1359 bytes .../main/resources/visualtest/html/solid.svg | 3 ++ .../visualtest/html/svg-custom-protocol.html | 19 +++++++++ .../html/svg-external-file-load-blocked.html | 19 +++++++++ ...external-file-whitelist-file-protocol.html | 19 +++++++++ .../VisualRegressionTest.java | 40 +++++++++++++++++- .../pdfboxout/PdfBoxRenderer.java | 4 ++ .../svgsupport/BatikSVGDrawer.java | 31 ++++++++++++-- .../svgsupport/BatikSVGImage.java | 13 ++++-- .../svgsupport/OpenHtmlDocumentLoader.java | 40 ++++++++++++++++++ .../svgsupport/OpenHtmlUserAgent.java | 8 +++- .../svgsupport/PDFTranscoder.java | 27 +++++++++--- 15 files changed, 216 insertions(+), 21 deletions(-) create mode 100644 openhtmltopdf-examples/src/main/resources/visualtest/expected/svg-custom-protocol.pdf create mode 100644 openhtmltopdf-examples/src/main/resources/visualtest/expected/svg-external-file-load-blocked.pdf create mode 100644 openhtmltopdf-examples/src/main/resources/visualtest/expected/svg-external-file-whitelist-file-protocol.pdf create mode 100644 openhtmltopdf-examples/src/main/resources/visualtest/html/solid.svg create mode 100644 openhtmltopdf-examples/src/main/resources/visualtest/html/svg-custom-protocol.html create mode 100644 openhtmltopdf-examples/src/main/resources/visualtest/html/svg-external-file-load-blocked.html create mode 100644 openhtmltopdf-examples/src/main/resources/visualtest/html/svg-external-file-whitelist-file-protocol.html create mode 100644 openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlDocumentLoader.java diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/SVGDrawer.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/SVGDrawer.java index 187f7e2b8..db4da5f6d 100644 --- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/SVGDrawer.java +++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/SVGDrawer.java @@ -12,18 +12,20 @@ import com.openhtmltopdf.render.RenderingContext; public interface SVGDrawer extends Closeable { - public void importFontFaceRules(List fontFaces, + void importFontFaceRules(List fontFaces, SharedContext shared); - public SVGImage buildSVGImage(Element svgElement, Box box, CssContext cssContext, double cssWidth, + SVGImage buildSVGImage(Element svgElement, Box box, CssContext cssContext, double cssWidth, double cssHeight, double dotsPerPixel); - public static interface SVGImage { - public int getIntrinsicWidth(); + default void withUserAgent(UserAgentCallback userAgentCallback) {} - public int getIntrinsicHeight(); + interface SVGImage { + int getIntrinsicWidth(); - public void drawSVG(OutputDevice outputDevice, RenderingContext ctx, + int getIntrinsicHeight(); + + void drawSVG(OutputDevice outputDevice, RenderingContext ctx, double x, double y); } } diff --git a/openhtmltopdf-examples/src/main/resources/visualtest/expected/svg-custom-protocol.pdf b/openhtmltopdf-examples/src/main/resources/visualtest/expected/svg-custom-protocol.pdf new file mode 100644 index 0000000000000000000000000000000000000000..142ad27981097a2ddd98452aaafebbf4b1b59624 GIT binary patch literal 1362 zcmah}O=uHA6b5Ulj8p^#QLzqcZB?3`+0EuhO2H(Jr1sC$+G>cfNv7$>WT$SXTE(ju zFU6j{h*D6of_hRf{R1ze6i=cQq+S#+q80zpH=Ayorh=2~B=csz_uhQpdt2Wfi8fJ> z7u7E={F+A;6UFob@;r-_lguuf+`t0WWLXiba6FD$S`f1` z5~h{G!!|Pn03wE9xG{2AB`P7hs!^{_G;)Zj4TLlt08cj045yim8~G5k21Ow+_)uoR zljem3Wv*qY)tNadAmx~uDdL1zW|Blom=9Y5(=wpkSqnr;2g{g7h>zd|@enK@&7Htc zw_!7IRJtH|wFE4SSeIdt5@$s|Y^Q+%pJP~IKpt?TwKFR#1~H{RnNCpvA%$85K{UUP zFCZ1SA%b&=65N3jNdRWhIk0F17Z6PF&CA~OUO-(a(L5j`EX^|vWHW?qI-&uI zQn1pqvPhPbJ#zhd*AX;DHa~rFXtDa!_~{R4?%@q}k7{;r&fV?5vHr`?&e!n|lTY?N z+;ToU78|W=2+bC5Rc-vX_raLB6TUxN-PP9d=4yOw|CQUZYnfbUyFImc=acI%(6*+! zTbEyT?&y0t{f@q!eE59N&ScYE^7rHKKc3FFoto{AO>Do}``%udPHka4s*ix^_wYy(x)n#^(66%1? z<%J>Wz*L@Vtq4HsXgQD{QI?l~rNW zw6!*!tc{`T(5w~Mpb9-$X)8Y`Y{Sem+j(WhIfv$Vh*DzK0LSu$1pOL|;6!sU7zwMP zz!4Jl`h!}ls;a>N^#!8T7gEDo#M^@Ze*~(s$GpTOe@;sqws07wgalB1eQQ?~{RO6T Bdz1hG literal 0 HcmV?d00001 diff --git a/openhtmltopdf-examples/src/main/resources/visualtest/expected/svg-external-file-load-blocked.pdf b/openhtmltopdf-examples/src/main/resources/visualtest/expected/svg-external-file-load-blocked.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0b3d6edd9cee270f07bf8e0bca582e73fd4e070e GIT binary patch literal 784 zcmah{!H&}~5WSDI|1g(ocZI0OcG9G%s>C*_w7`l|5FDyKgvM>NYUAR#V&P}G@C}?e zFwVBSg&r6sb}}<>=J|~~lWhE4b|dKg`uY0@NF=nM?_e+h@!{LnpcoatSlcCtkH$5X ztx?Es0%B4uO@oTlr!X9XsmlP_jZ9_0}*L{5PqZcJGf zSN0xf)FlkBJ}g{kQaHnf9uCM=YtO$8#-R;}scG!a%~^q7>v&QiBpkZEG4;}~FpUD6 z#eP4YyEI~Vx!ueK{sIQ^Z$={CQ4>@na$p8QV literal 0 HcmV?d00001 diff --git a/openhtmltopdf-examples/src/main/resources/visualtest/expected/svg-external-file-whitelist-file-protocol.pdf b/openhtmltopdf-examples/src/main/resources/visualtest/expected/svg-external-file-whitelist-file-protocol.pdf new file mode 100644 index 0000000000000000000000000000000000000000..364f59930d15006bedce85f6586c8525336ea13b GIT binary patch literal 1359 zcmah}-AhzK6bGRXh6F*Ph_FH0G_Ace_wL2$d^ZT7Mz7`|4 zm-++9w=nzrJ))Rk9`8dnHArb6%rLCfo5Hks4^ldqlTC3OE7TuCN{iXUvRH-ft*EvZ zF*_+?S{}UKVWt3pVG4%JjeROn3DH%J1_Bx-l|(Hgq--~Ma(J>o!5m!9GtBN4X-n`- zvfH2F>D_s*WvG>zxhWv!P%4?lodKCi7gFkZzb!D$1Im@PK%_LWWXg>20o+Oa1j|?R z2Jq8jIt(1;4hUXt0n;qjWf-KivMld+62L&vH7qkAH+azwGrLFhVoHNDovZ*t(uD|u zXdxY+Mk;PZ1ot6Ia1-k60$>uI0*gj)8o>ZxOa3kbELh6>>#p{qqsRu3l#O5t*-+xw zaUzYB7hPoWejmw+dgOx#QKSaZCOB?OkL=Wrodb%k9%nKXF-?_@#UE0aYR zNNMYj3%78jqkN{M^XPy$*d}B_guMVtWQ7Ja3_{2OG>D}v0d=9oEI=46!IKPRGli3K zMFSG0V7YgB(v?s4z>TTqI`o7TJ$hcbux@Vj_?MI8cw@=Lh8;zHW4Buhew{5#mzTct z%?y*_w};nn3g2yi)A$W%-j`N36kj+#R9rGK@?hQg&gqJ_OBIzbZd|*(XDHq}xWD>@ zHIJ`c3Jso^Dmi~}}NYJZm;>_4}UIr_VMYT zn;qwFz5G5=QT=N3p_!kbwrm?6`daw^l5iCUyY znxJiYIs@$&w^&{)3^=SCs)!OqmL43`bxp_JP?(Dk1zzQY?IjxxLcmov5`rXG*;EzE zYL!jX*4lKkHioW4r>??Q(Y0}_bf|W3pK#2S#T@s(YULa{-z7?Eu)8^yw-GdJgMmA1 zs1^)_2{9r@G^puyF + + diff --git a/openhtmltopdf-examples/src/main/resources/visualtest/html/svg-custom-protocol.html b/openhtmltopdf-examples/src/main/resources/visualtest/html/svg-custom-protocol.html new file mode 100644 index 000000000..15a0df61b --- /dev/null +++ b/openhtmltopdf-examples/src/main/resources/visualtest/html/svg-custom-protocol.html @@ -0,0 +1,19 @@ + + + + + + + + + + \ No newline at end of file diff --git a/openhtmltopdf-examples/src/main/resources/visualtest/html/svg-external-file-load-blocked.html b/openhtmltopdf-examples/src/main/resources/visualtest/html/svg-external-file-load-blocked.html new file mode 100644 index 000000000..4800bf78e --- /dev/null +++ b/openhtmltopdf-examples/src/main/resources/visualtest/html/svg-external-file-load-blocked.html @@ -0,0 +1,19 @@ + + + + + + + + + + \ No newline at end of file diff --git a/openhtmltopdf-examples/src/main/resources/visualtest/html/svg-external-file-whitelist-file-protocol.html b/openhtmltopdf-examples/src/main/resources/visualtest/html/svg-external-file-whitelist-file-protocol.html new file mode 100644 index 000000000..4800bf78e --- /dev/null +++ b/openhtmltopdf-examples/src/main/resources/visualtest/html/svg-external-file-whitelist-file-protocol.html @@ -0,0 +1,19 @@ + + + + + + + + + + \ No newline at end of file diff --git a/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/visualregressiontests/VisualRegressionTest.java b/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/visualregressiontests/VisualRegressionTest.java index 65c04c110..1bbc7745e 100644 --- a/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/visualregressiontests/VisualRegressionTest.java +++ b/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/visualregressiontests/VisualRegressionTest.java @@ -1,8 +1,13 @@ package com.openhtmltopdf.visualregressiontests; -import java.io.File; +import java.io.*; + import static org.junit.Assert.assertTrue; -import java.io.IOException; + +import java.nio.charset.StandardCharsets; +import java.util.Collections; + +import com.openhtmltopdf.extend.FSStream; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; @@ -1118,6 +1123,37 @@ public void testIssue484ImgSrcDataImageSvgBase64() throws IOException { assertTrue(vt.runTest("issue-484-data-image-svg-xml-base64", TestSupport.WITH_SVG)); } + + @Test + public void testSVGLoadBlocked() throws IOException { + assertTrue(vt.runTest("svg-external-file-load-blocked", TestSupport.WITH_SVG)); + } + + @Test + public void testSVGLoadWhiteListFileProtocol() throws IOException { + assertTrue(vt.runTest("svg-external-file-whitelist-file-protocol", + (builder) -> builder.useSVGDrawer(new BatikSVGDrawer(SvgScriptMode.SECURE, Collections.singleton("file"))))); + } + + @Test + public void testSVGLoadCustomProtocol() throws IOException { + assertTrue(vt.runTest("svg-custom-protocol", (builder -> { + builder.useProtocolsStreamImplementation(url -> new FSStream() { + + @Override + public InputStream getStream() { + return new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8)); + } + + @Override + public Reader getReader() { + return new InputStreamReader(getStream(), StandardCharsets.UTF_8); + } + }, "custom"); + builder.useSVGDrawer(new BatikSVGDrawer(SvgScriptMode.SECURE, Collections.singleton("custom"))); + }))); + } + // TODO: // + Elements that appear just on generated overflow pages. // + content property (page counters, etc) diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java index 57c798811..631d51a49 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java @@ -163,6 +163,10 @@ public class PdfBoxRenderer implements Closeable, PageSupplier { PdfBoxUserAgent userAgent = new PdfBoxUserAgent(_outputDevice); + if (_svgImpl != null) { + _svgImpl.withUserAgent(userAgent); + } + userAgent.setProtocolsStreamFactory(state._streamFactoryMap); if (state._resolver != null) { diff --git a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/BatikSVGDrawer.java b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/BatikSVGDrawer.java index 14e67c0bc..9fe79f3f8 100644 --- a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/BatikSVGDrawer.java +++ b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/BatikSVGDrawer.java @@ -1,8 +1,11 @@ package com.openhtmltopdf.svgsupport; import java.io.IOException; +import java.util.Collections; import java.util.List; +import java.util.Set; +import com.openhtmltopdf.extend.UserAgentCallback; import org.w3c.dom.Element; import com.openhtmltopdf.css.sheet.FontFaceRule; @@ -14,16 +17,18 @@ import com.openhtmltopdf.svgsupport.PDFTranscoder.OpenHtmlFontResolver; public class BatikSVGDrawer implements SVGDrawer { + private final Set allowedProtocols; public OpenHtmlFontResolver fontResolver; private final boolean allowScripts; private final boolean allowExternalResources; + private UserAgentCallback userAgentCallback; - public static enum SvgScriptMode { + public enum SvgScriptMode { SECURE, INSECURE_ALLOW_SCRIPTS; } - public static enum SvgExternalResourceMode { + public enum SvgExternalResourceMode { SECURE, INSECURE_ALLOW_EXTERNAL_RESOURCE_REQUESTS; } @@ -40,6 +45,20 @@ public static enum SvgExternalResourceMode { public BatikSVGDrawer(SvgScriptMode scriptMode, SvgExternalResourceMode externalResourceMode) { this.allowScripts = scriptMode == SvgScriptMode.INSECURE_ALLOW_SCRIPTS; this.allowExternalResources = externalResourceMode == SvgExternalResourceMode.INSECURE_ALLOW_EXTERNAL_RESOURCE_REQUESTS; + this.allowedProtocols = null; + } + + /** + * Creates a SVGDrawer that can allow arbitary scripts to run and allow the loading of + * external resources with the specified protocols. + * + * @param scriptMode + * @param allowedProtocols + */ + public BatikSVGDrawer(SvgScriptMode scriptMode, Set allowedProtocols) { + this.allowScripts = scriptMode == SvgScriptMode.INSECURE_ALLOW_SCRIPTS; + this.allowExternalResources = false; + this.allowedProtocols = Collections.unmodifiableSet(allowedProtocols); } /** @@ -59,6 +78,11 @@ public void importFontFaceRules(List fontFaces, this.fontResolver.importFontFaces(fontFaces, shared); } + @Override + public void withUserAgent(UserAgentCallback userAgentCallback) { + this.userAgentCallback = userAgentCallback; + } + @Override public SVGImage buildSVGImage(Element svgElement, Box box, CssContext c, double cssWidth, double cssHeight, double dotsPerPixel) { @@ -69,7 +93,8 @@ public SVGImage buildSVGImage(Element svgElement, Box box, CssContext c, BatikSVGImage img = new BatikSVGImage(svgElement, box, cssWidth, cssHeight, cssMaxWidth, cssMaxHeight, dotsPerPixel); img.setFontResolver(fontResolver); - img.setSecurityOptions(allowScripts, allowExternalResources); + img.setUserAgentCallback(userAgentCallback); + img.setSecurityOptions(allowScripts, allowExternalResources, allowedProtocols); return img; } diff --git a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/BatikSVGImage.java b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/BatikSVGImage.java index cab3cf8cb..e2b7a215f 100644 --- a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/BatikSVGImage.java +++ b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/BatikSVGImage.java @@ -1,8 +1,10 @@ package com.openhtmltopdf.svgsupport; import java.awt.Point; +import java.util.Set; import java.util.logging.Level; +import com.openhtmltopdf.extend.UserAgentCallback; import org.apache.batik.anim.dom.SVGDOMImplementation; import org.apache.batik.transcoder.SVGAbstractTranscoder; import org.apache.batik.transcoder.TranscoderException; @@ -28,6 +30,7 @@ public class BatikSVGImage implements SVGImage { private final double dotsPerPixel; private OpenHtmlFontResolver fontResolver; private final PDFTranscoder pdfTranscoder; + private UserAgentCallback userAgentCallback; public BatikSVGImage(Element svgElement, Box box, double cssWidth, double cssHeight, double cssMaxWidth, double cssMaxHeight, double dotsPerPixel) { @@ -98,10 +101,14 @@ public void setFontResolver(OpenHtmlFontResolver fontResolver) { this.fontResolver = fontResolver; } - public void setSecurityOptions(boolean allowScripts, boolean allowExternalResources) { - this.pdfTranscoder.setSecurityOptions(allowScripts, allowExternalResources); + public void setSecurityOptions(boolean allowScripts, boolean allowExternalResources, Set allowedProtocols) { + this.pdfTranscoder.setSecurityOptions(allowScripts, allowExternalResources, allowedProtocols); this.pdfTranscoder.addTranscodingHint(SVGAbstractTranscoder.KEY_EXECUTE_ONLOAD, allowScripts); } + + public void setUserAgentCallback(UserAgentCallback userAgentCallback) { + this.userAgentCallback = userAgentCallback; + } public Integer parseLength(String attrValue) { // TODO read length with units and convert to dots. @@ -159,7 +166,7 @@ public void drawSVG(OutputDevice outputDevice, RenderingContext ctx, } pdfTranscoder.setRenderingParameters(outputDevice, ctx, x, y, - fontResolver); + fontResolver, userAgentCallback); try { DOMImplementation impl = SVGDOMImplementation diff --git a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlDocumentLoader.java b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlDocumentLoader.java new file mode 100644 index 000000000..2381582f5 --- /dev/null +++ b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlDocumentLoader.java @@ -0,0 +1,40 @@ +package com.openhtmltopdf.svgsupport; + +import com.openhtmltopdf.extend.UserAgentCallback; +import com.openhtmltopdf.util.XRLog; +import org.apache.batik.bridge.DocumentLoader; +import org.apache.batik.bridge.UserAgent; +import org.w3c.dom.Document; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +public class OpenHtmlDocumentLoader extends DocumentLoader { + + private final UserAgentCallback userAgentCallback; + + public OpenHtmlDocumentLoader(UserAgent userAgent, UserAgentCallback userAgentCallback) { + super(userAgent); + this.userAgentCallback = userAgentCallback; + } + + + @Override + public Document loadDocument(String uri) throws IOException { + try { + // special handling of relative uri in case of file protocol, we receive something like "file:file.svg" + // The path will be null, but the scheme specific part will be not null + URI parsedURI = new URI(uri); + if ("file".equals(parsedURI.getScheme()) && parsedURI.getPath() == null && parsedURI.getSchemeSpecificPart() != null) { + uri = userAgentCallback.resolveURI(parsedURI.getSchemeSpecificPart()); + } else if (!parsedURI.isAbsolute()) { + uri = userAgentCallback.resolveURI(uri); + } + } catch (URISyntaxException uriSyntaxException) { + XRLog.exception("URI syntax exception while loading external svg resource: " + uri, uriSyntaxException); + } + return super.loadDocument(uri, new ByteArrayInputStream(userAgentCallback.getBinaryResource(uri))); + } +} diff --git a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlUserAgent.java b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlUserAgent.java index ee619c6a5..fe78470a3 100644 --- a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlUserAgent.java +++ b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlUserAgent.java @@ -7,16 +7,20 @@ import com.openhtmltopdf.svgsupport.PDFTranscoder.OpenHtmlFontResolver; import com.openhtmltopdf.util.XRLog; +import java.util.Set; + public class OpenHtmlUserAgent extends UserAgentAdapter { private final OpenHtmlFontResolver resolver; private final boolean allowScripts; private final boolean allowExternalResources; + private final Set allowedProtocols; - public OpenHtmlUserAgent(OpenHtmlFontResolver resolver, boolean allowScripts, boolean allowExternalResources) { + public OpenHtmlUserAgent(OpenHtmlFontResolver resolver, boolean allowScripts, boolean allowExternalResources, Set allowedProtocols) { this.resolver = resolver; this.allowScripts = allowScripts; this.allowExternalResources = allowExternalResources; + this.allowedProtocols = allowedProtocols; } @Override @@ -34,7 +38,7 @@ public void checkLoadScript(String scriptType, ParsedURL scriptURL, ParsedURL do @Override public void checkLoadExternalResource(ParsedURL resourceURL, ParsedURL docURL) throws SecurityException { - if (!this.allowExternalResources) { + if (!this.allowExternalResources && (allowedProtocols == null || !allowedProtocols.contains(resourceURL.getProtocol()))) { XRLog.exception("Tried to fetch external resource from SVG. Refusing. Details: " + resourceURL + ", " + docURL); throw new SecurityException("Tried to fetch external resource (" + resourceURL + ") from SVG. Refused!"); } diff --git a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFTranscoder.java b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFTranscoder.java index 3a8ef5939..c83d54c50 100644 --- a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFTranscoder.java +++ b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFTranscoder.java @@ -7,13 +7,16 @@ import com.openhtmltopdf.css.style.FSDerivedValue; import com.openhtmltopdf.extend.OutputDevice; import com.openhtmltopdf.extend.OutputDeviceGraphicsDrawer; +import com.openhtmltopdf.extend.UserAgentCallback; import com.openhtmltopdf.layout.SharedContext; import com.openhtmltopdf.render.Box; import com.openhtmltopdf.render.RenderingContext; import com.openhtmltopdf.simple.extend.ReplacedElementScaleHelper; import com.openhtmltopdf.util.XRLog; +import org.apache.batik.bridge.BridgeContext; import org.apache.batik.bridge.FontFace; import org.apache.batik.bridge.FontFamilyResolver; +import org.apache.batik.bridge.svg12.SVG12BridgeContext; import org.apache.batik.gvt.font.GVTFontFamily; import org.apache.batik.transcoder.ErrorHandler; import org.apache.batik.transcoder.SVGAbstractTranscoder; @@ -28,6 +31,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; public class PDFTranscoder extends SVGAbstractTranscoder { private OpenHtmlFontResolver fontResolver; @@ -39,6 +43,8 @@ public class PDFTranscoder extends SVGAbstractTranscoder { private final double dotsPerPixel; private boolean allowScripts = false; private boolean allowExternalResources = false; + private UserAgentCallback userAgentCallback; + private Set allowedProtocols; public PDFTranscoder(Box box, double dotsPerPixel, double width, double height) { this.box = box; @@ -47,12 +53,13 @@ public PDFTranscoder(Box box, double dotsPerPixel, double width, double height) this.dotsPerPixel = dotsPerPixel; } - public void setRenderingParameters(OutputDevice od, RenderingContext ctx, double x, double y, OpenHtmlFontResolver fontResolver) { + public void setRenderingParameters(OutputDevice od, RenderingContext ctx, double x, double y, OpenHtmlFontResolver fontResolver, UserAgentCallback userAgentCallback) { this.x = x; this.y = y; this.outputDevice = od; this.ctx = ctx; this.fontResolver = fontResolver; + this.userAgentCallback = userAgentCallback; } @Override @@ -201,18 +208,28 @@ public void importFontFaces(List fontFaces, SharedContext ctx) { } } } - - public void setSecurityOptions(boolean allowScripts, boolean allowExternalResources) { + + public void setSecurityOptions(boolean allowScripts, boolean allowExternalResources, Set allowedProtocols) { this.allowScripts = allowScripts; this.allowExternalResources = allowExternalResources; + this.allowedProtocols = allowedProtocols; } - + + @Override + protected BridgeContext createBridgeContext(String svgVersion) { + if ("1.2".equals(svgVersion)) { + return new SVG12BridgeContext(userAgent, new OpenHtmlDocumentLoader(userAgent, userAgentCallback)); + } else { + return new BridgeContext(userAgent, new OpenHtmlDocumentLoader(userAgent, userAgentCallback)); + } + } + @Override protected void transcode(Document svg, String uri, TranscoderOutput out) throws TranscoderException { // Note: We have to initialize user agent here and not in ::createUserAgent() as method // is called before our constructor is called in the super constructor. - this.userAgent = new OpenHtmlUserAgent(this.fontResolver, this.allowScripts, this.allowExternalResources); + this.userAgent = new OpenHtmlUserAgent(this.fontResolver, this.allowScripts, this.allowExternalResources, this.allowedProtocols); super.transcode(svg, uri, out); Rectangle contentBounds = box.getContentAreaEdge(box.getAbsX(), box.getAbsY(), ctx);