Using Flying Saucer 10.7.0: Grid, @font-face and Java 21
A dashboard template with a two-column CSS grid and a net total that a script writes after load prints as one column with no total when Flying Saucer renders it. The renderer ships for Java as org.xhtmlrenderer:flying-sa
A dashboard template with a two-column CSS grid and a net total that a script writes after load prints as one column with no total when Flying Saucer renders it. The renderer ships for Java as org.xhtmlrenderer:flying-saucer-pdf, and 10.7.0, released 24 October 2026, is its current version. We ran into that grid while testing the library for this post, so it comes first, and later sections draw on more 10.7.0 runs, the R8 user's guide, the code and what NVD, GHSA and OSV record.
We work at Iron Software, and the end of this article covers our library, IronPDF.
What Does Flying Saucer Do With CSS Grid and a Script-Written Total?
It lays the grid items out as ordinary blocks and drops the script. The engine targets CSS 2.1, extended with its own -fs- print properties and some later CSS. A set in the code, CSSName.UNSUPPORTED_CSS3_PROPERTIES, names 52 CSS3 properties that layout passes over, grid and flexbox among them, and the R8 user's guide says script tags are ignored.
import org.xhtmlrenderer.pdf.ITextRenderer;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class GridScriptCards {
public static void main(String[] args) throws Exception {
// A two-column grid with a total that a script writes after load, as many dashboards do.
String xhtml = "<html><head><style>"
+ ".grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }"
+ ".tile { padding: 10px; border: 1px solid #999; }"
+ "</style></head><body>"
+ "<div class='grid'><div class='tile'>Orders 412</div><div class='tile'>Returns 9</div></div>"
+ "<p id='total'></p>"
+ "<script>document.getElementById('total').textContent = 'Net orders 403';</script>"
+ "</body></html>";
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(xhtml);
renderer.layout();
try (OutputStream out = new FileOutputStream("grid-script-cards.pdf")) {
renderer.createPDF(out);
}
}
}
grid-script-cards.pdf is a single US Letter page with Orders 412 above Returns 9 at the same left margin, and the text layer has no Net orders 403. During the run the Html5Support logger printed one warning naming display: grid, grid-template-columns and gap as unsupported, then the PDF was written as normal. That warning, first logged in 10.2.0, is the only sign of the problem. Any template a front-end team designs in a browser is affected, and the routes around it are a float and table layout or the project's separate Chrome module, covered below.
Does @font-face Embed the Font in the PDF?
Not with the CSS a browser accepts. A plain @font-face rule resolves the font for layout, but the PDF only names it, so the reader's viewer has to supply the face.
import org.xhtmlrenderer.pdf.ITextRenderer;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.nio.file.Path;
public class FontFaceCss {
public static void main(String[] args) throws Exception {
// The same @font-face rule a browser would use, with the TTF resolved against the base URL.
String xhtml = "<html><head><style>"
+ "@font-face { font-family: 'Brand'; src: url('georgia.ttf'); }"
+ "h1 { font-family: 'Brand'; }"
+ "</style></head><body><h1>Quarterly summary</h1></body></html>";
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(xhtml, Path.of("fonts").toUri().toString());
renderer.layout();
try (OutputStream out = new FileOutputStream("font-face.pdf")) {
renderer.createPDF(out);
}
}
}
The heading in font-face.pdf references a TrueType font called Georgia with no font file in its descriptor, so on a machine without Georgia the viewer substitutes another face. Adding the vendor property -fs-pdf-font-embed: embed to the rule, which the user's guide documents, produced an embedded Georgia subset in a second run. Brand fonts depend on embedding. So does the PDF/A archive format, an ISO preservation standard whose rule 6.2.11.4.1 requires all fonts embedded, and it has a second font catch. With a font registered as BaseFont.IDENTITY_H and PDF/A-3b requested, veraPDF 1.30.3 failed the output on the CIDSet rule 6.2.11.4.2, while BaseFont.CP1252 passed for Western European text.
Can CMS HTML Go Straight Into setDocumentFromString?
No. The parser is XML, and the user's guide says most HTML found in the wild can't be rendered and should go through TagSoup, JTidy or a similar cleaner first.
import org.xhtmlrenderer.pdf.ITextRenderer;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class RawCmsFragment {
public static void main(String[] args) throws Exception {
// Valid HTML5 as a browser reads it, with an unclosed <p> and <li> and a bare <br>.
String html = "<h1>Release notes</h1>"
+ "<p>Version 3.2 ships today.<br>Highlights:"
+ "<ul><li>Faster search<li>New export menu</ul>";
ITextRenderer renderer = new ITextRenderer();
// The XML parser rejects the string here, before layout starts.
renderer.setDocumentFromString(html);
renderer.layout();
try (OutputStream out = new FileOutputStream("release-notes.pdf")) {
renderer.createPDF(out);
}
}
}
The run stopped in setDocumentFromString with XRRuntimeException wrapping a SAX error at line 1, column 24, saying the markup following the root element must be well-formed, and no file was written. Parsing with jsoup and passing its W3CDom result to setDocument rendered this fragment in a test run, and it adds a dependency and a step to every render.
Which Advisories Show Up in a Dependency Scan?
Mostly history rather than the current release, with one recent batch in a dependency.
-
Builds through 9.3.2: A default
flying-saucer-pdfbuild resolvescom.lowagie:itext2.1.7, and GitHub's GHSA-86p9-x5pw-94qx flags that artifact for CVE-2017-9096 at every version up to 4.2.2, with no fixed version. - CVE-2017-9096 scores 8.8 High under CVSS 3.0 (NIST): An XXE weakness in iText's XML parsing, which NIST also scores 6.8 on CVSS 2 and NVD doesn't tag as disputed.
- OpenPDF from 9.4.0: It took over the PDF layer at that release, which came out at the end of December 2023.
-
XXE changes with no CVE: Two hardening changes, one to
XMLResourcein 9.12.1 (June 2025) and one toDocumentBuilderFactoryin 10.4.0 (July 2026), shipped with no CVE identifier, which leaves scanners blind to builds that lack them. - Advisories on the current tree: Neither OSV nor GHSA lists any advisory for a Flying Saucer artifact, and OSV, queried for the libraries 10.7.0 pulls in on 3 November 2026, had nothing for them either. The exception is Apache's Batik page, which names seven medium-rated CVEs in 1.19, the version 10.7.0 pulls in, and everything older, all patched by the 1.20 release of 20 October 2026.
Teams still on 9.3.2 or earlier carry the iText finding. Moving to 10.4.0 or later picks up the iText and XXE changes, while the Batik fixes need a release that moves off 1.19, and none had reached Maven Central on 3 November 2026.
What Changes With the Chrome Module and the Java 21 Floor?
The Chrome module trades the CSS gap for a browser to manage, and the 10.x line needs a recent JVM.
The module, flying-saucer-chrome-pdf, first shipped with 10.3.0 in June 2026 and hands each page to chrome-headless-shell. Unless told otherwise it asks Google's chrome-for-testing feed for the current Stable build and refreshes that answer daily, so the browser doing the printing changes underneath the application, and on 3 November 2026 that answer was build 156.0.8078.80. Calling setChromeVersion pins it. Two more details in the 10.7.0 source matter in production. The print call fires on Page.loadEventFired with no dedicated delay setting in ChromiumPdfOptions (a desktop Chrome run needed addExtraArg("--virtual-time-budget=5000") in one-shot mode to print a late script's text), and on Linux arm64 the platform check throws even though the chrome-for-testing JSON offers linux-arm64 downloads for Stable. The exception suggests setBinaryPath, yet the check runs before that path is read, and a test with os.name Linux and os.arch aarch64 still threw with a path supplied.
Java is the other constraint. Since 10.0.0 in September 2025, every 10.x jar targets Java 21 (class file 65), and compiling against 10.7.0 with the JDK 17 javac failed with a wrong-version error in the test run. Java 17 projects are held to 9.x, where 9.13.4 is the newest build. Separately, the parent POM leaves slf4j-api to the application as a provided dependency, and without it constructing the first renderer threw NoClassDefFoundError.
Where Does IronPDF for Java Fit These Checks?
If the trade-offs above don't fit a project, IronPDF for Java is a commercial library that prints HTML through Chromium. On 2026.11.3, our run of the grid above put Orders 412 and Returns 9 in two columns and printed Net orders 403 from the script. Scripts run by default, since ChromePdfRenderOptions starts with setEnableJavaScript on, a WaitFor can pause the capture for a fixed delay, network idle or a named element, raw CMS HTML needs no jsoup pass, and PDF/A-3b output is one saveAsPdfA call.
The library itself is com.ironsoftware:ironpdf on Maven Central, built as Java 8 bytecode, with eleven 2026 builds by 3 November 2026, numbered by month, the newest published that day. The engine it bundles or downloads is pinned by each IronPDF release, so a Chromium update arrives only as an IronPDF version bump. A free trial is available for testing it against your own templates.
Summing Up the Flying Saucer Checklist
Grid and script missing from the PDF, unembedded @font-face fonts, an XML-only parser, a Chrome module that follows the Stable channel and a Java 21 floor are the checks this post ran on Flying Saucer 10.7.0, and the iText 2.1.7 dependency behind CVE-2017-9096 belongs to pre-9.4.0 builds. For pages built for a browser, IronPDF for Java renders them in Chromium from a single dependency, and our HTML file example shows the call.
Flying Saucer, OpenPDF, iText, Apache Batik, Georgia, Chrome and veraPDF are trademarks of their respective owners, we have no affiliation with any of them, and the details above come from each project's source, documentation, release notes and the NVD, GHSA and OSV databases.
Drafted with AI. Flying Saucer code run and claims checked by the Iron Software DevRel team on 3 November 2026, with IronPDF APIs checked against com.ironsoftware:ironpdf 2026.11.3.
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.