Flying Saucer Project: FAQ

This is our list of frequently-asked questions. For a more comprehensive guide, see our User's Guide. Please contact us on our mailing list if you have more questions.

General Questions

  1. What is Flying Saucer?
  2. Wait a second! XML, XHTML, get your story straight!
  3. Does Flying Saucer support legacy HTML?
  4. Can I use Flying Saucer to browse websites?
  5. Is Flying Saucer a web browser?
  6. What kind of applications can I use Flying Saucer for?
  7. What XHTML/CSS features does Flying Saucer currently support?
  8. What XHTML/CSS features is Flying Saucer missing?
  9. So do you pass the Acid(2) test?

What is Flying Saucer?

Flying Saucer is an XHTML renderer written in Java. It's 100% Java, not a native wrapper, and it only handles well-formed XHTML + CSS. It is intended for embedding web-based user interfaces into Java applications (ex. web photo album generator, help viewer, iTunes Music Store clone). It cannot be used as a general purpose web browser since it does not support the malformed legacy HTML found on the web, though recent work on compatibility libraries may be enough to do what you need. You may be able to work with legacy HTML (e.g. HTML that is not well-formed XML) by using a pre-processor that cleans it up; there are several of these, including JTidy and TagSoup. See our User's Guide for details.

Wait a second! XML, XHTML, get your story straight!

Flying Saucer takes well-formed XML (or a DOM Document) as input, matches it with CSS (linked, inline, attributed) and renders it. That XML could, for example, be XHTML (strict). We figure most of you are interested in rendering some form of XHTML, so in these docs we use "XHTML" as short for "well-formed XML, for example, XHTML (strict)".

You can render any XML, in fact, as long as you have CSS for it. For XHTML, we have out-of-the-box default CSS styling; for any other XML, you'll need to bring your own.

Does Flying Saucer support legacy HTML?

Can I use Flying Saucer to browse websites?

Flying Saucer is not an HTML component. It is a rendering component for XHTML content, but it cannot handle the malformed HTML 4.0 of general webpages, and it has no support for purely stylistic markup like FONT and CENTER. You have to use valid XHTML and CSS. For most embedded uses this is fine since the application author usually has control over the documents to be loaded. If you really need full IE/Mozilla/Safari-like fidelity for general purpose webpages you should look into a webbrowser wrapper like JDIC's Browser component, or a commercial component like WebRenderer. Sun's Swing team has said they are working on a Java wrapper for WebKit called JWebPane, but there is no release schedule announced so far.

Is Flying Saucer a web browser?

The core renderer just handles XHTML and CSS. It doesn't know anything about form submission, managing cookies, or tracki ng the browsing history. It just renders XHTML/CSS to the screen. However, Flying Saucer does include a (very simple) Browser application which shows how you might develop these features yourself. You can use this as a good starting point for your own applications.

What kind of applications can I use Flying Saucer for?

Flying Saucer can be used for any Java application that requires some sort of styled content, to generate high-quality PDF output based on XHTML and CSS documents, or to layout and render images based on XHTML and CSS.

An application using Flying Saucer can be as simple as a chat program or as complicated as a complete ebook reader with dynamic stylesheets. Flying Saucer is very forward- thinking and is designed to be a part of the next generation of applications that combine rich desktop clients with web content. Some examples of application types are:

Flying Saucer has become a favorite recently for people who need to render clean XHTML to PDF; we support PDF output via the iText library.

What XHTML/CSS features does Flying Saucer currently support?

Flying Saucer supports all of CSS 2.1 with a few exceptions. Consult the issue tracker for more information on what is not supported (in particular, the issues with a summary of "Support ...") or ask on the mailing list.

If you do encounter a compliance bug or other unexpected behavior, please open a bug or post to the mailing list. Our goal is 100% compliance with the CSS 2.1 specification.

What XHTML/CSS features is Flying Saucer missing?

Check the issue tracker for a list or ask on the mailing list if you aren't sure.

Among other things there is no support for things outside the scope of XHTML/CSS such as Javascript, Flash, or legacy HTML (though there is interest in all of those).

So do you pass the Acid(2) test?

Our core developer in the R7 development cycle, Pete Brant, reported that it was possible to render Acid2 pretty well, with some caveats. Quoting from him in the developer's email list:

begin quote

"Save for the changes below, test_as_xml.xml is an unmodified version of http://hixie.ch/tests/evil/acid/002-no-data/. All in all things are looking good!

Changes to original test:

  1. Replace DOCTYPE with one we recognize to pick up entity references (in particular  )
  2. Wrap <style> tag in CDATA
  3. Close open tags as appropriate (in particular, <p> and table related tags in row 1 [as referenced from the test guide], <link> in header, and bottom <img> (after row 14 in guide)
  4. Replace <object data="data007">ERROR</object> with <img src="data007">ERROR</img> (since we don't support HTML's <object> )
  5. Change CSS selector on line 55 from "#eyes-a object object object" to "#eyes-a object object img" to compensate for (4)
  6. Bottom <img> uses a data URL even in the non-data URL version (I assume it was just missed). Save data URL contents to disk (as data008) and update src attribute

Of course, these changes mean that we cannot claim Acid2 compliance, but nothing there changes the nature of the test (at least as far as a CSS torture test goes).

Besides those changes above, there are still the following compliance problems:

  1. The transparent pixels in the eyes row background(s) are painted as black. Weird considering that the alpha channel in the eyes graphic itself is apparently picked up fine.
  2. Hover doesn't work on generated content (hence no blue nose on mouseover)
  3. There shouldn't be a scroll bar on the page by virtue of @html { overflow: hidden; }@"

end quote

The resulting image is available on our project home page, as an Easter egg. See if you can find the little bandit.

Usage Questions

  1. How do I make my program follow hyperlinks?
  2. How do I get access to the Swing components that make up my form fields?
  3. I have XML or XHTML stored in a Java String, not a file—how do I load this into an XHTMLPanel?
  4. How do I force Anti-aliasing?
  5. When I use the setDocument(dom, url) constructor, what should the url parameter point to?
  6. How do i get the starting index of selected text?
  7. How can I "watermark" PDF's created through FS?
  8. I've created a replacedelementfactory for a custom XML element (e.g. MathML), but it's not getting replaced within the document.
  9. My PDF isn't picking up my CSS!
  10. How can I print multiple pages on to one PDF, if they come from multiple documents?
  11. Can I use Flying Saucer in an SWT application?
  12. My header is not showing up correctly in my PDF.
  13. How do I set a custom UserAgentCallback when generating PDF?
  14. How do I figure out the size of a document I'm rendering? Can I get this from the renderer? How about preferred size of XHTMLPanel? Why isn't my panel properly sized on screen?

How do I make my program follow hyperlinks?

You need a mouse listener that detects link clicks and does the HTTP request. The BasicPanel supports tracking mouse events and delegating them to FSMouseListener instances. You can use the org.xhtmlrenderer.swing.LinkListener class, which implements FSMouseListener, for basic hyperlink navigation support.

How do I get access to the Swing components that make up my form fields?

Take a look at the org.xhtmlrenderer.simple.extend.XhtmlForm class. Form elements are "replaced" at runtime by the org.xhtmlrenderer.swing.SwingReplacedElementFactory if you're using the XHTMLPanel class for rendering. The factory actually creates a new XhtmlForm class which creates and tracks the components. To receive a callback when the user submits a form, add a FormSubmissionListener instance to your BasicPanel.

I have XML or XHTML stored in a Java String, not a file—how do I load this into an XHTMLPanel?

It's been tricky for us to come up with a decent set of method calls to cover initilizing the panel without creating tons of little methods.

In Java APIs, there is some confusion on usage between a String that represents an address (like a URI or a file path) and strings that represent content. Our API tends to expect that Strings will represent addresses.

You can use panel.setDocumentFromString() to render a document from a string containing XHTML content. The String will be passed to the standard XML parser and treated as a regular document.

It's important to remember that FS expects well-formed XML documents, and we don't have an extremely friendly relationship with the XML parsers; it's always a good idea to test that your document can be loaded outside of FS, without error, using Java XML APIs, before loading them in FS. This is especially true if you are generating XHTML on-the-fly.

How do I force Anti-aliasing?

Either
* Set the appropriate configuration properties: xr.text.aa-fontsize-threshhold
* Get the Java2DTextRenderer reference from the XHTMLPanel's SharedContext property, then call setSmoothingThreshold()

The threshold is the font size at which AA should kick in, for text; font sizes below that size will not be drawn with AA. A threshold of -1 turns AA off completely.

Note that on some platforms and JREs, AA can slow things down considerably. It appears to be much better with more recent Sun JREs, such as Java 6.

When I use the setDocument(dom, url) constructor, what should the url parameter point to?

The url is the "base", which for a normal URL would be the parent location—the parent directory, or the location where the document you are rendering is located.

If your document has absolute URIs for CSS and images, or it has no external references at all, then the base url can be null.

If your document has any relative URIs for CSS or images, then the base URL should not be null, but rather should point to the directory or address where the current document is located.

How do i get the starting index of selected text?

_I am using the selection / highlighting capabilities in Flying Saucer. Hightlighting works fine, but I need to have the index of the selection. Is this possible?

That's not possible out of the box. The DOM interface doesn't provide position information. An option is to walk through the nodes of the document to the left of the start of the selected range and then adding all the text content lengths.

How can I "watermark" PDF's created through FS?

Either use the background property inside of @page or PdfStamper after the PDF is already created. PdfStamper is part of the iText API.

I've created a replacedelementfactory for a custom XML element (e.g. MathML), but it's not getting replaced within the document.

Make sure the element has it's display style as inline-block or block. Only block-level elements can be replaced.

My PDF isn't picking up my CSS!

PDF is treated as "print" media; see the CSS 2.1 specification section on media types. Make sure you have specified the media type for your CSS when you link or embed it; use type "print" or "all".

How can I print multiple pages on to one PDF, if they come from multiple documents?

For the first document in the set (e.g. starting with the first page in the PDF you want to render) take an ITextRenderer and call setDocument(), layout() and createPDF(); for each subsequent document, use the same renderer and call setDocument(), layout(), and writeNextDocument(). Call finishPDF() to complete the process. A sample follows below; a cleaned-up example, PDFRenderToMultiplePages, is in our demos/samples directory in our source distribution.

String root = "J:/Temp/fs";

String[] inputs = new String[] { "input1.html", "input2.html",
"input3.html" };
String output = "output.pdf";

OutputStream os = null;
try
{
   os = new FileOutputStream(new File(root, output));

   ITextRenderer renderer = new ITextRenderer();

   renderer.setDocument(new File(root, inputs[0]));
   renderer.layout();

   renderer.createPDF(os, false);

   for (int i = 1; i < inputs.length; i++)
   {
       renderer.setDocument(new File(root, inputs[i]));
       renderer.layout();
       renderer.writeNextDocument();
   }

   renderer.finishPDF();

   os.close();
   os = null;
}
finally
{
   if (os != null)
   {
       try
       {
           os.close();
       }
       catch (IOException e)
       {
           // ignore
       }
   }
}

Can I use Flying Saucer in an SWT application?

If you're trying to output to an SWT canvas—there is an early mockup by Vianney le Clément which we plan to merge in the R8 release. See the mailing list thread starting with:
https://xhtmlrenderer.dev.java.net/servlets/ReadMsg?listName=dev&msgNo=3452

There are patches attached to that mail thread which provide initial support for SWT; some things are still missing, but it's a good start.

My header is not showing up correctly in my PDF.

The values of -fs-flow-top/right/bottom/left and -fs-move-to-flow must
be strings and not keywords (e.g. -fs-flow-top: 'header' instead of
-fs-flow-top: header ).

The new CSS parser validates this (and will give you a warning message if you have logging turned on).

How do I set a custom UserAgentCallback when generating PDF?

ITextRenderer renderer = new ITextRenderer();

ITextUserAgent callback = new ITextUserAgent(renderer.getOutputDevice());
callback.setSharedContext(renderer.getSharedContext());
renderer.getSharedContext().setUserAgentCallback(callback);

renderer.setDocument(url);
renderer.layout();
renderer.createPDF(os);

How do I figure out the size of a document I'm rendering? Can I get this from the renderer? How about preferred size of XHTMLPanel? Why isn't my panel properly sized on screen?

The rules are that the document size is calculated after a layout takes place; for rendering to a Swing panel, this can only happen if the container for the panel (e.g. the window) is displayable. See this email thread in our mailing list for a discussion. In our demos/samples directory in the source distribution, the PanelResizeToPreferredSize and JPanelSizeToDocument show how this is done. Basically (quoting from the mail thread):

"So basically you want to:

  1. create the frame and add components to it
  2. call f.pack() to make them displayable
  3. layout documents in XHTMLPanel instances using doDocumentLayout(graphics)
  4. call f.pack() again now that the preferred size of the XHTMLPanel instances has been calculated"

If you are relying on a layout manager that itself relies on its components' preferred sizes (like FlowLayout) you need to make sure to follow the rules above in order for the layout manager to pick up the size of the panel after it has been layed out. The second call to pack() after doDocumentLayout() takes care of doing this. See PanelResizeToPreferredSize for an example using FlowLayout.

Developer's FAQ

  1. How do I set up my CLASSPATH?
  2. How do I build XR without Ant?
  3. How do I build XR from within my IDE?

How do I set up my CLASSPATH?

You only need the

The first two are required; iText is needed for PDF rendering.

In earlier releases, you needed to include a CSS parser in the CLASSPATH. This is no longer necessary, as Flying Saucer now includes a fast, compliant CSS parser.

That is all you need for your own programs. You also need an XML parser to be in your classpath, but this already included in recent versions of the JRE.

To run the browser or use any of it's support classes you will need the browser.jar file.

How do I build XR without Ant?

How do I build XR from within my IDE?

Our Ant build.xml file includes all JAR files in the /lib directory, plus the /resources directory tree in the classpath. The compile target also copies CSS and properties resources from /src/css and src/conf to /build/resources. If running from an IDE, you will need to synchronize this yourself.