From a9d282b09ed06070928f3567a2f0c00900efd124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mu=CC=88ller?= Date: Wed, 20 Nov 2024 08:43:36 +0100 Subject: [PATCH] PDF: Allow style elements inside inlined SVGs Some SVG files contain style elements. These need to remain inside the html that is sent to Flying Saucer, so that Apache Batik can pick them up. Fixes: SE-13745 --- .../pdf/TagliatellePDFContentHandler.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/sirius/web/templates/pdf/TagliatellePDFContentHandler.java b/src/main/java/sirius/web/templates/pdf/TagliatellePDFContentHandler.java index a96d3433a..ad9cb2800 100644 --- a/src/main/java/sirius/web/templates/pdf/TagliatellePDFContentHandler.java +++ b/src/main/java/sirius/web/templates/pdf/TagliatellePDFContentHandler.java @@ -10,6 +10,7 @@ import org.jsoup.Jsoup; import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; import org.jsoup.nodes.Entities; import org.xhtmlrenderer.pdf.ITextRenderer; import sirius.kernel.di.std.Part; @@ -21,6 +22,7 @@ import sirius.web.templates.TagliatelleContentHandler; import java.io.OutputStream; +import java.util.function.Predicate; /** * Generates a PDF output by evaluating a given tagliatelle template which must result in a valid XHTML dom. @@ -85,10 +87,8 @@ private String cleanHtml(String html) { document.head().appendChild(bookmarks); }); - // in theory, the following two lines should be possible with a single CSS selector; however, in practice, Jsoup - // does not select the style elements correctly when attempting that document.select("script").remove(); - document.select("body style").remove(); + document.select("body style").removeIf(Predicate.not(this::isElementInsideSvg)); document.outputSettings().syntax(Document.OutputSettings.Syntax.xml); document.outputSettings().escapeMode(Entities.EscapeMode.xhtml); @@ -96,6 +96,16 @@ private String cleanHtml(String html) { return document.html(); } + /** + * Determine whether the given element is part of an SVG element by checking all ancestors. + * + * @param element the element to check + * @return true if the element is part of an SVG, false otherwise + */ + private boolean isElementInsideSvg(Element element) { + return element.closest("svg") != null; + } + @Override public int getPriority() { return DEFAULT_PRIORITY;